Java源碼之Hashtable

來源:互聯網
上載者:User

Java源碼之Hashtable

一、Hashtable概述

類實現一個雜湊表,該雜湊表將鍵key對象映射到相應的值value對象。要求key和value都非null。為了成功地在雜湊表中儲存和擷取對象,用作鍵的對象必須實現 hashCode 方法和 equals 方法。

Hashtable是線程同步的,但是非線程同步的HashMap完全可以取代它。

如果不需要安全執行緒,可以直接使用HashMap取代;

如果需要安全執行緒高並發,可以使用java.util.concurrent.ConcurrentHashMap取代。

二、Hashtable資料結構

Hashtable與jdk1.8之前的HashMap一樣,是用數組+鏈表實現。

/** * Hashtable數組衝突鏈結點 */private static class Entry implements Map.Entry {    final int hash;    final K key;    V value;    Entry next; // 下一個結點    protected Entry(int hash, K key, V value, Entry next) {        this.hash = hash;        this.key =  key;        this.value = value;        this.next = next;    }    @SuppressWarnings("unchecked")    protected Object clone() {        return new Entry<>(hash, key, value,                              (next==null ? null : (Entry) next.clone()));    }    // Map.Entry Ops    public K getKey() {        return key;    }    public V getValue() {        return value;    }    public V setValue(V value) {        if (value == null)            throw new NullPointerException();        V oldValue = this.value;        this.value = value;        return oldValue;    }    public boolean equals(Object o) {        if (!(o instanceof Map.Entry))            return false;        Map.Entry e = (Map.Entry)o;        return (key==null ? e.getKey()==null : key.equals(e.getKey())) &&           (value==null ? e.getValue()==null : value.equals(e.getValue()));    }    public int hashCode() {        return hash ^ Objects.hashCode(value);    }    public String toString() {        return key.toString()+"="+value.toString();    }}

三、Hashtable源碼

1.標頭檔

package java.util;import java.io.*;import java.util.concurrent.ThreadLocalRandom;import java.util.function.BiConsumer;import java.util.function.Function;import java.util.function.BiFunction;

2.實現與繼承

public class Hashtableextends Dictionaryimplements Map, Cloneable, java.io.Serializable

3.屬性

/** * hash表數組 */private transient Entry[] table;/** * 數組中儲存的元素個數 */private transient int count;/** * 閾值,超過這個值數組要擴容 * threshold = capacity * loadFactor */private int threshold;/** * 裝載因子 */private float loadFactor;/** * 修改次數 * 採用fail-fast機制 */private transient int modCount = 0;


 

4.構造器與方法

這部分與HashMap的主要區別是,hash函數的演算法。

這裡用的是典型的除留取餘法:

 

int index = (hash & 0x7FFFFFFF) % tab.length;

 

這部分的構造器、方法與HashMap的差別不大,只是在方法前面加了synchronized使方法同步。

/** * 構造方法一: * 用指定容量 + 指定裝載因子構造 */public Hashtable(int initialCapacity, float loadFactor) {    if (initialCapacity < 0)        throw new IllegalArgumentException("Illegal Capacity: "+                                           initialCapacity);    if (loadFactor <= 0 || Float.isNaN(loadFactor))        throw new IllegalArgumentException("Illegal Load: "+loadFactor);    if (initialCapacity==0)        initialCapacity = 1;    this.loadFactor = loadFactor;    table = new Entry[initialCapacity];    threshold = (int)Math.min(initialCapacity * loadFactor, MAX_ARRAY_SIZE + 1);}/** * 構造方法二: * 指定容量 + 預設裝載因子構造 */public Hashtable(int initialCapacity) {    this(initialCapacity, 0.75f);}/** * 構造方法三: * 使用預設容量11 + 預設裝載因子 */public Hashtable() {    this(11, 0.75f);}/** * 構造方法四: * 使用Map構造 */public Hashtable(Map t) {    this(Math.max(2*t.size(), 11), 0.75f);    putAll(t);}/** * 返回容量大小 */public synchronized int size() {    return count;}/** * 判空 */public synchronized boolean isEmpty() {    return count == 0;}/** * 返回所有key值的枚舉集合 */public synchronized Enumeration keys() {    return this.getEnumeration(KEYS);}/** * 返回所有value值的枚舉集合 */public synchronized Enumeration elements() {    return this.getEnumeration(VALUES);}/** * 判斷是否包含value值對象 */public synchronized boolean contains(Object value) {    if (value == null) {        throw new NullPointerException();    }    Entry tab[] = table;    for (int i = tab.length ; i-- > 0 ;) {        for (Entry e = tab[i] ; e != null ; e = e.next) {            if (e.value.equals(value)) {                return true;            }        }    }    return false;}/** * 判斷是否包含value值對象 */public boolean containsValue(Object value) {    return contains(value);}/** * 判斷是否包含key索引值對象 */public synchronized boolean containsKey(Object key) {    Entry tab[] = table;    int hash = key.hashCode();    int index = (hash & 0x7FFFFFFF) % tab.length;    for (Entry e = tab[index] ; e != null ; e = e.next) {        if ((e.hash == hash) && e.key.equals(key)) {            return true;        }    }    return false;}/** * 擷取索引值key對應的value */@SuppressWarnings("unchecked")public synchronized V get(Object key) {    Entry tab[] = table;    int hash = key.hashCode();    int index = (hash & 0x7FFFFFFF) % tab.length;    for (Entry e = tab[index] ; e != null ; e = e.next) {        if ((e.hash == hash) && e.key.equals(key)) {            return (V)e.value;        }    }    return null;}/** * 規定的最大數組容量 */private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;/** * 擴容(2*oldCap  + 1) */@SuppressWarnings("unchecked")protected void rehash() {    int oldCapacity = table.length;    Entry[] oldMap = table;    // overflow-conscious code    int newCapacity = (oldCapacity << 1) + 1;    if (newCapacity - MAX_ARRAY_SIZE > 0) {        if (oldCapacity == MAX_ARRAY_SIZE)            // Keep running with MAX_ARRAY_SIZE buckets            return;        newCapacity = MAX_ARRAY_SIZE;    }    Entry[] newMap = new Entry[newCapacity];    modCount++;    threshold = (int)Math.min(newCapacity * loadFactor, MAX_ARRAY_SIZE + 1);    table = newMap;    for (int i = oldCapacity ; i-- > 0 ;) {        for (Entry old = (Entry)oldMap[i] ; old != null ; ) {            Entry e = old;            old = old.next;            int index = (e.hash & 0x7FFFFFFF) % newCapacity;            e.next = (Entry)newMap[index];            newMap[index] = e;        }    }}private void addEntry(int hash, K key, V value, int index) {    modCount++;    Entry tab[] = table;    if (count >= threshold) {        // Rehash the table if the threshold is exceeded        rehash();        tab = table;        hash = key.hashCode();        index = (hash & 0x7FFFFFFF) % tab.length;    }    // Creates the new entry.    @SuppressWarnings("unchecked")    Entry e = (Entry) tab[index];    tab[index] = new Entry<>(hash, key, value, e);    count++;}/** * 添加元素 * 原key索引值存在,返回原key鍵對應的value * 原key索引值不存在,返回null */public synchronized V put(K key, V value) {    // Make sure the value is not null    if (value == null) {        throw new NullPointerException();    }    // Makes sure the key is not already in the hashtable.    Entry tab[] = table;    int hash = key.hashCode();    int index = (hash & 0x7FFFFFFF) % tab.length;    @SuppressWarnings("unchecked")    Entry entry = (Entry)tab[index];    for(; entry != null ; entry = entry.next) {        if ((entry.hash == hash) && entry.key.equals(key)) {            V old = entry.value;            entry.value = value;            return old;        }    }    addEntry(hash, key, value, index);    return null;}/** * 刪除並返回要刪除的value */public synchronized V remove(Object key) {    Entry tab[] = table;    int hash = key.hashCode();    int index = (hash & 0x7FFFFFFF) % tab.length;    @SuppressWarnings("unchecked")    Entry e = (Entry)tab[index];    for(Entry prev = null ; e != null ; prev = e, e = e.next) {        if ((e.hash == hash) && e.key.equals(key)) {            modCount++;            if (prev != null) {                prev.next = e.next;            } else {                tab[index] = e.next;            }            count--;            V oldValue = e.value;            e.value = null;            return oldValue;        }    }    return null;}/** * 將Map中的元素添加進來 */public synchronized void putAll(Map t) {    for (Map.Entry e : t.entrySet())        put(e.getKey(), e.getValue());}/** * 清空 */public synchronized void clear() {    Entry tab[] = table;    modCount++;    for (int index = tab.length; --index >= 0; )        tab[index] = null;    count = 0;}/** * 複製對象 */public synchronized Object clone() {    try {        Hashtable t = (Hashtable)super.clone();        t.table = new Entry[table.length];        for (int i = table.length ; i-- > 0 ; ) {            t.table[i] = (table[i] != null)                ? (Entry) table[i].clone() : null;        }        t.keySet = null;        t.entrySet = null;        t.values = null;        t.modCount = 0;        return t;    } catch (CloneNotSupportedException e) {        // this shouldn't happen, since we are Cloneable        throw new InternalError(e);    }}private  Enumeration getEnumeration(int type) {    if (count == 0) {        return Collections.emptyEnumeration();    } else {        return new Enumerator<>(type, false);    }}// 獲得迭代器private  Iterator getIterator(int type) {    if (count == 0) {        return Collections.emptyIterator();    } else {        return new Enumerator<>(type, true);    }}// Views/** * Each of these fields are initialized to contain an instance of the * appropriate view the first time this view is requested.  The views are * stateless, so there's no reason to create more than one of each. */private transient volatile Set keySet;private transient volatile Set> entrySet;private transient volatile Collection values;/** * 返回包含此map的Set視圖 * 通過Set視圖可獲得迭代器Iterator對象,對map進行迭代 */public Set> entrySet() {    if (entrySet==null)        entrySet = Collections.synchronizedSet(new EntrySet(), this);    return entrySet;}// Set視圖類private class EntrySet extends AbstractSet> {    public Iterator> iterator() {        return getIterator(ENTRIES);    }    public boolean add(Map.Entry o) {        return super.add(o);    }    public boolean contains(Object o) {        if (!(o instanceof Map.Entry))            return false;        Map.Entry entry = (Map.Entry)o;        Object key = entry.getKey();        Entry[] tab = table;        int hash = key.hashCode();        int index = (hash & 0x7FFFFFFF) % tab.length;        for (Entry e = tab[index]; e != null; e = e.next)            if (e.hash==hash && e.equals(entry))                return true;        return false;    }    public boolean remove(Object o) {        if (!(o instanceof Map.Entry))            return false;        Map.Entry entry = (Map.Entry) o;        Object key = entry.getKey();        Entry[] tab = table;        int hash = key.hashCode();        int index = (hash & 0x7FFFFFFF) % tab.length;        @SuppressWarnings("unchecked")        Entry e = (Entry)tab[index];        for(Entry prev = null; e != null; prev = e, e = e.next) {            if (e.hash==hash && e.equals(entry)) {                modCount++;                if (prev != null)                    prev.next = e.next;                else                    tab[index] = e.next;                count--;                e.value = null;                return true;            }        }        return false;    }    public int size() {        return count;    }    public void clear() {        Hashtable.this.clear();    }}/** * Returns a {@link Collection} view of the values contained in this map. * The collection is backed by the map, so changes to the map are * reflected in the collection, and vice-versa.  If the map is * modified while an iteration over the collection is in progress * (except through the iterator's own remove operation), * the results of the iteration are undefined.  The collection * supports element removal, which removes the corresponding * mapping from the map, via the Iterator.remove, * Collection.remove, removeAll, * retainAll and clear operations.  It does not * support the add or addAll operations. * * @since 1.2 */public Collection values() {    if (values==null)        values = Collections.synchronizedCollection(new ValueCollection(),                                                    this);    return values;}private class ValueCollection extends AbstractCollection {    public Iterator iterator() {        return getIterator(VALUES);    }    public int size() {        return count;    }    public boolean contains(Object o) {        return containsValue(o);    }    public void clear() {        Hashtable.this.clear();    }}// Comparison and hashing/** * 實現equals * 判等 */public synchronized boolean equals(Object o) {    if (o == this)        return true;    if (!(o instanceof Map))        return false;    Map t = (Map) o;    if (t.size() != size())        return false;    try {        Iterator> i = entrySet().iterator();        while (i.hasNext()) {            Map.Entry e = i.next();            K key = e.getKey();            V value = e.getValue();            if (value == null) {                if (!(t.get(key)==null && t.containsKey(key)))                    return false;            } else {                if (!value.equals(t.get(key)))                    return false;            }        }    } catch (ClassCastException unused)   {        return false;    } catch (NullPointerException unused) {        return false;    }    return true;}/** * 實現hashCode */public synchronized int hashCode() {    /*     * This code detects the recursion caused by computing the hash code     * of a self-referential hash table and prevents the stack overflow     * that would otherwise result.  This allows certain 1.1-era     * applets with self-referential hash tables to work.  This code     * abuses the loadFactor field to do double-duty as a hashCode     * in progress flag, so as not to worsen the space performance.     * A negative load factor indicates that hash code computation is     * in progress.     */    int h = 0;    if (count == 0 || loadFactor < 0)        return h;  // Returns zero    loadFactor = -loadFactor;  // Mark hashCode computation in progress    Entry[] tab = table;    for (Entry entry : tab) {        while (entry != null) {            h += entry.hashCode();            entry = entry.next;        }    }    loadFactor = -loadFactor;  // Mark hashCode computation complete    return h;}@Overridepublic synchronized boolean replace(K key, V oldValue, V newValue) {    Objects.requireNonNull(oldValue);    Objects.requireNonNull(newValue);    Entry tab[] = table;    int hash = key.hashCode();    int index = (hash & 0x7FFFFFFF) % tab.length;    @SuppressWarnings("unchecked")    Entry e = (Entry)tab[index];    for (; e != null; e = e.next) {        if ((e.hash == hash) && e.key.equals(key)) {            if (e.value.equals(oldValue)) {                e.value = newValue;                return true;            } else {                return false;            }        }    }    return false;}/* * 替換 */@Overridepublic synchronized V replace(K key, V value) {    Objects.requireNonNull(value);    Entry tab[] = table;    int hash = key.hashCode();    int index = (hash & 0x7FFFFFFF) % tab.length;    @SuppressWarnings("unchecked")    Entry e = (Entry)tab[index];    for (; e != null; e = e.next) {        if ((e.hash == hash) && e.key.equals(key)) {            V oldValue = e.value;            e.value = value;            return oldValue;        }    }    return null;}

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.