深入Java集合學習系列:Hashtable的實現原理


第1部分 Hashtable介紹

  和HashMap一樣,Hashtable也是一個散列表,它存儲的內容是鍵值對(key-value)映射。Hashtable繼承於Dictionary,實現了Map、Cloneable、java.io.Serializable接口。Hashtable的函數都是同步的,這意味着它是線程安全的。它的key、value都不可以為null。此外,Hashtable中的映射不是有序的。Hashtable的實例有兩個參數影響其性能:初始容量和加載因子。容量是哈希表桶的數量,初始容量就是哈希表創建時的容量。注意,哈希表的狀態為 open:在發生“哈希沖突”的情況下,單個桶會存儲多個條目,這些條目必須按順序搜索。加載因子是對哈希表在其容量自動增加之前可以達到多滿的一個尺度。初始容量和加載因子這兩個參數只是對該實現的提示。關於何時以及是否調用rehash方法的具體細節則依賴於該實現。通常,默認加載因子是 0.75, 這是在時間和空間成本上尋求一種折衷。加載因子過高雖然減少了空間開銷,但同時也增加了查找某個條目的時間。

第2部分 Hashtable數據結構

java.lang.Object
   ↳     java.util.Dictionary<K, V>
         ↳     java.util.Hashtable<K, V>

public class Hashtable<K,V> extends Dictionary<K,V>
    implements Map<K,V>, Cloneable, java.io.Serializable { }

  Hashtable與Map關系如下圖:

從圖中可以看出:

  (01) Hashtable繼承於Dictionary類,實現了Map接口。Map是"key-value鍵值對"接口,Dictionary是聲明了操作"鍵值對"函數接口的抽象類。 
  (02) Hashtable是通過"拉鏈法"實現的哈希表。它包括幾個重要的成員變量:table, count, threshold, loadFactor, modCount。
  table是一個Entry[]數組類型,而Entry實際上就是一個單向鏈表。哈希表的"key-value鍵值對"都是存儲在Entry數組中的。count是Hashtable的大小,它是Hashtable保存的鍵值對的數量。threshold是Hashtable的閾值,用於判斷是否需要調整Hashtable的容量。threshold的值="容量*加載因子"。loadFactor就是加載因子。 modCount是用來實現fail-fast機制的

第3部分 Hashtable源碼解析(基於JDK1.6.0_45)

package java.util; import java.io.*; public class Hashtable<K,V>
    extends Dictionary<K,V>
    implements Map<K,V>, Cloneable, java.io.Serializable { // Hashtable保存key-value的數組。 // Hashtable是采用拉鏈法實現的,每一個Entry本質上是一個單向鏈表
    private transient Entry[] table; // Hashtable中元素的實際數量
    private transient int count; // 閾值,用於判斷是否需要調整Hashtable的容量(threshold = 容量*加載因子)
    private int threshold; // 加載因子
    private float loadFactor; // Hashtable被改變的次數
    private transient int modCount = 0; // 序列版本號
    private static final long serialVersionUID = 1421746759512286392L; // 指定“容量大小”和“加載因子”的構造函數
    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)(initialCapacity * loadFactor); } // 指定“容量大小”的構造函數
    public Hashtable(int initialCapacity) { this(initialCapacity, 0.75f); } // 默認構造函數。
    public Hashtable() { // 默認構造函數,指定的容量大小是11;加載因子是0.75
        this(11, 0.75f); } // 包含“子Map”的構造函數
    public Hashtable(Map<? extends K, ? extends V> t) { this(Math.max(2*t.size(), 11), 0.75f); // 將“子Map”的全部元素都添加到Hashtable中
 putAll(t); } public synchronized int size() { return count; } public synchronized boolean isEmpty() { return count == 0; } // 返回“所有key”的枚舉對象
    public synchronized Enumeration<K> keys() { return this.<K>getEnumeration(KEYS); } // 返回“所有value”的枚舉對象
    public synchronized Enumeration<V> elements() { return this.<V>getEnumeration(VALUES); } // 判斷Hashtable是否包含“值(value)”
    public synchronized boolean contains(Object value) { // Hashtable中“鍵值對”的value不能是null, // 若是null的話,拋出異常!
        if (value == null) { throw new NullPointerException(); } // 從后向前遍歷table數組中的元素(Entry) // 對於每個Entry(單向鏈表),逐個遍歷,判斷節點的值是否等於value
        Entry tab[] = table; for (int i = tab.length ; i-- > 0 ;) { for (Entry<K,V> e = tab[i] ; e != null ; e = e.next) { if (e.value.equals(value)) { return true; } } } return false; } public boolean containsValue(Object value) { return contains(value); } // 判斷Hashtable是否包含key
    public synchronized boolean containsKey(Object key) { Entry tab[] = table; int hash = key.hashCode(); // 計算索引值, // % tab.length 的目的是防止數據越界
        int index = (hash & 0x7FFFFFFF) % tab.length; // 找到“key對應的Entry(鏈表)”,然后在鏈表中找出“哈希值”和“鍵值”與key都相等的元素
        for (Entry<K,V> e = tab[index] ; e != null ; e = e.next) { if ((e.hash == hash) && e.key.equals(key)) { return true; } } return false; } // 返回key對應的value,沒有的話返回null
    public synchronized V get(Object key) { Entry tab[] = table; int hash = key.hashCode(); // 計算索引值,
        int index = (hash & 0x7FFFFFFF) % tab.length; // 找到“key對應的Entry(鏈表)”,然后在鏈表中找出“哈希值”和“鍵值”與key都相等的元素
        for (Entry<K,V> e = tab[index] ; e != null ; e = e.next) { if ((e.hash == hash) && e.key.equals(key)) { return e.value; } } return null; } // 調整Hashtable的長度,將長度變成原來的(2倍+1) // (01) 將“舊的Entry數組”賦值給一個臨時變量。 // (02) 創建一個“新的Entry數組”,並賦值給“舊的Entry數組” // (03) 將“Hashtable”中的全部元素依次添加到“新的Entry數組”中
    protected void rehash() { int oldCapacity = table.length; Entry[] oldMap = table; int newCapacity = oldCapacity * 2 + 1; Entry[] newMap = new Entry[newCapacity]; modCount++; threshold = (int)(newCapacity * loadFactor); table = newMap; for (int i = oldCapacity ; i-- > 0 ;) { for (Entry<K,V> old = oldMap[i] ; old != null ; ) { Entry<K,V> e = old; old = old.next; int index = (e.hash & 0x7FFFFFFF) % newCapacity; e.next = newMap[index]; newMap[index] = e; } } } // 將“key-value”添加到Hashtable中
    public synchronized V put(K key, V value) { // Hashtable中不能插入value為null的元素!!!
        if (value == null) { throw new NullPointerException(); } // 若“Hashtable中已存在鍵為key的鍵值對”, // 則用“新的value”替換“舊的value”
        Entry tab[] = table; int hash = key.hashCode(); int index = (hash & 0x7FFFFFFF) % tab.length; for (Entry<K,V> e = tab[index] ; e != null ; e = e.next) { if ((e.hash == hash) && e.key.equals(key)) { V old = e.value; e.value = value; return old; } } // 若“Hashtable中不存在鍵為key的鍵值對”, // (01) 將“修改統計數”+1
        modCount++; // (02) 若“Hashtable實際容量” > “閾值”(閾值=總的容量 * 加載因子) // 則調整Hashtable的大小
        if (count >= threshold) { // Rehash the table if the threshold is exceeded
 rehash(); tab = table; index = (hash & 0x7FFFFFFF) % tab.length; } // (03) 將“Hashtable中index”位置的Entry(鏈表)保存到e中
        Entry<K,V> e = tab[index]; // (04) 創建“新的Entry節點”,並將“新的Entry”插入“Hashtable的index位置”,並設置e為“新的Entry”的下一個元素(即“新Entry”為鏈表表頭)。 
        tab[index] = new Entry<K,V>(hash, key, value, e); // (05) 將“Hashtable的實際容量”+1
        count++; return null; } // 刪除Hashtable中鍵為key的元素
    public synchronized V remove(Object key) { Entry tab[] = table; int hash = key.hashCode(); int index = (hash & 0x7FFFFFFF) % tab.length; // 找到“key對應的Entry(鏈表)” // 然后在鏈表中找出要刪除的節點,並刪除該節點。
        for (Entry<K,V> e = tab[index], 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(t)”的中全部元素逐一添加到Hashtable中
    public synchronized void putAll(Map<? extends K, ? extends V> t) { for (Map.Entry<? extends K, ? extends V> e : t.entrySet()) put(e.getKey(), e.getValue()); } // 清空Hashtable // 將Hashtable的table數組的值全部設為null
    public synchronized void clear() { Entry tab[] = table; modCount++; for (int index = tab.length; --index >= 0; ) tab[index] = null; count = 0; } // 克隆一個Hashtable,並以Object的形式返回。
    public synchronized Object clone() { try { Hashtable<K,V> t = (Hashtable<K,V>) super.clone(); t.table = new Entry[table.length]; for (int i = table.length ; i-- > 0 ; ) { t.table[i] = (table[i] != null) ? (Entry<K,V>) 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(); } } public synchronized String toString() { int max = size() - 1; if (max == -1) return "{}"; StringBuilder sb = new StringBuilder(); Iterator<Map.Entry<K,V>> it = entrySet().iterator(); sb.append('{'); for (int i = 0; ; i++) { Map.Entry<K,V> e = it.next(); K key = e.getKey(); V value = e.getValue(); sb.append(key == this ? "(this Map)" : key.toString()); sb.append('='); sb.append(value == this ? "(this Map)" : value.toString()); if (i == max) return sb.append('}').toString(); sb.append(", "); } } // 獲取Hashtable的枚舉類對象 // 若Hashtable的實際大小為0,則返回“空枚舉類”對象; // 否則,返回正常的Enumerator的對象。(Enumerator實現了迭代器和枚舉兩個接口)
    private <T> Enumeration<T> getEnumeration(int type) { if (count == 0) { return (Enumeration<T>)emptyEnumerator; } else { return new Enumerator<T>(type, false); } } // 獲取Hashtable的迭代器 // 若Hashtable的實際大小為0,則返回“空迭代器”對象; // 否則,返回正常的Enumerator的對象。(Enumerator實現了迭代器和枚舉兩個接口)
    private <T> Iterator<T> getIterator(int type) { if (count == 0) { return (Iterator<T>) emptyIterator; } else { return new Enumerator<T>(type, true); } } // Hashtable的“key的集合”。它是一個Set,意味着沒有重復元素
    private transient volatile Set<K> keySet = null; // Hashtable的“key-value的集合”。它是一個Set,意味着沒有重復元素
    private transient volatile Set<Map.Entry<K,V>> entrySet = null; // Hashtable的“key-value的集合”。它是一個Collection,意味着可以有重復元素
    private transient volatile Collection<V> values = null; // 返回一個被synchronizedSet封裝后的KeySet對象 // synchronizedSet封裝的目的是對KeySet的所有方法都添加synchronized,實現多線程同步
    public Set<K> keySet() { if (keySet == null) keySet = Collections.synchronizedSet(new KeySet(), this); return keySet; } // Hashtable的Key的Set集合。 // KeySet繼承於AbstractSet,所以,KeySet中的元素沒有重復的。
    private class KeySet extends AbstractSet<K> { public Iterator<K> iterator() { return getIterator(KEYS); } public int size() { return count; } public boolean contains(Object o) { return containsKey(o); } public boolean remove(Object o) { return Hashtable.this.remove(o) != null; } public void clear() { Hashtable.this.clear(); } } // 返回一個被synchronizedSet封裝后的EntrySet對象 // synchronizedSet封裝的目的是對EntrySet的所有方法都添加synchronized,實現多線程同步
    public Set<Map.Entry<K,V>> entrySet() { if (entrySet==null) entrySet = Collections.synchronizedSet(new EntrySet(), this); return entrySet; } // Hashtable的Entry的Set集合。 // EntrySet繼承於AbstractSet,所以,EntrySet中的元素沒有重復的。
    private class EntrySet extends AbstractSet<Map.Entry<K,V>> { public Iterator<Map.Entry<K,V>> iterator() { return getIterator(ENTRIES); } public boolean add(Map.Entry<K,V> o) { return super.add(o); } // 查找EntrySet中是否包含Object(0) // 首先,在table中找到o對應的Entry(Entry是一個單向鏈表) // 然后,查找Entry鏈表中是否存在Object
        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; } // 刪除元素Object(0) // 首先,在table中找到o對應的Entry(Entry是一個單向鏈表) // 然后,刪除鏈表中的元素Object
        public boolean remove(Object o) { if (!(o instanceof Map.Entry)) return false; Map.Entry<K,V> entry = (Map.Entry<K,V>) o; K key = entry.getKey(); Entry[] tab = table; int hash = key.hashCode(); int index = (hash & 0x7FFFFFFF) % tab.length; for (Entry<K,V> e = tab[index], 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(); } } // 返回一個被synchronizedCollection封裝后的ValueCollection對象 // synchronizedCollection封裝的目的是對ValueCollection的所有方法都添加synchronized,實現多線程同步
    public Collection<V> values() { if (values==null) values = Collections.synchronizedCollection(new ValueCollection(), this); return values; } // Hashtable的value的Collection集合。 // ValueCollection繼承於AbstractCollection,所以,ValueCollection中的元素可以重復的。
    private class ValueCollection extends AbstractCollection<V> { public Iterator<V> iterator() { return getIterator(VALUES); } public int size() { return count; } public boolean contains(Object o) { return containsValue(o); } public void clear() { Hashtable.this.clear(); } } // 重新equals()函數 // 若兩個Hashtable的所有key-value鍵值對都相等,則判斷它們兩個相等
    public synchronized boolean equals(Object o) { if (o == this) return true; if (!(o instanceof Map)) return false; Map<K,V> t = (Map<K,V>) o; if (t.size() != size()) return false; try { // 通過迭代器依次取出當前Hashtable的key-value鍵值對 // 並判斷該鍵值對,存在於Hashtable(o)中。 // 若不存在,則立即返回false;否則,遍歷完“當前Hashtable”並返回true。
            Iterator<Map.Entry<K,V>> i = entrySet().iterator(); while (i.hasNext()) { Map.Entry<K,V> 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; } // 計算Hashtable的哈希值 // 若 Hashtable的實際大小為0 或者 加載因子<0,則返回0。 // 否則,返回“Hashtable中的每個Entry的key和value的異或值 的總和”。
    public synchronized int hashCode() { int h = 0; if (count == 0 || loadFactor < 0) return h;  // Returns zero
 loadFactor = -loadFactor;  // Mark hashCode computation in progress
        Entry[] tab = table; for (int i = 0; i < tab.length; i++) for (Entry e = tab[i]; e != null; e = e.next) h += e.key.hashCode() ^ e.value.hashCode(); loadFactor = -loadFactor;  // Mark hashCode computation complete

        return h; } // java.io.Serializable的寫入函數 // 將Hashtable的“總的容量,實際容量,所有的Entry”都寫入到輸出流中
    private synchronized void writeObject(java.io.ObjectOutputStream s) throws IOException { // Write out the length, threshold, loadfactor
 s.defaultWriteObject(); // Write out length, count of elements and then the key/value objects
 s.writeInt(table.length); s.writeInt(count); for (int index = table.length-1; index >= 0; index--) { Entry entry = table[index]; while (entry != null) { s.writeObject(entry.key); s.writeObject(entry.value); entry = entry.next; } } } // java.io.Serializable的讀取函數:根據寫入方式讀出 // 將Hashtable的“總的容量,實際容量,所有的Entry”依次讀出
    private void readObject(java.io.ObjectInputStream s) throws IOException, ClassNotFoundException { // Read in the length, threshold, and loadfactor
 s.defaultReadObject(); // Read the original length of the array and number of elements
        int origlength = s.readInt(); int elements = s.readInt(); // Compute new size with a bit of room 5% to grow but // no larger than the original size. Make the length // odd if it's large enough, this helps distribute the entries. // Guard against the length ending up zero, that's not valid.
        int length = (int)(elements * loadFactor) + (elements / 20) + 3; if (length > elements && (length & 1) == 0) length--; if (origlength > 0 && length > origlength) length = origlength; Entry[] table = new Entry[length]; count = 0; // Read the number of elements and then all the key/value objects
        for (; elements > 0; elements--) { K key = (K)s.readObject(); V value = (V)s.readObject(); // synch could be eliminated for performance
 reconstitutionPut(table, key, value); } this.table = table; } private void reconstitutionPut(Entry[] tab, K key, V value) throws StreamCorruptedException { if (value == null) { throw new java.io.StreamCorruptedException(); } // Makes sure the key is not already in the hashtable. // This should not happen in deserialized version.
        int hash = key.hashCode(); int index = (hash & 0x7FFFFFFF) % tab.length; for (Entry<K,V> e = tab[index] ; e != null ; e = e.next) { if ((e.hash == hash) && e.key.equals(key)) { throw new java.io.StreamCorruptedException(); } } // Creates the new entry.
        Entry<K,V> e = tab[index]; tab[index] = new Entry<K,V>(hash, key, value, e); count++; } // Hashtable的Entry節點,它本質上是一個單向鏈表。 // 也因此,我們才能推斷出Hashtable是由拉鏈法實現的散列表
    private static class Entry<K,V> implements Map.Entry<K,V> { // 哈希值
        int hash; K key; V value; // 指向的下一個Entry,即鏈表的下一個節點
        Entry<K,V> next; // 構造函數
        protected Entry(int hash, K key, V value, Entry<K,V> next) { this.hash = hash; this.key = key; this.value = value; this.next = next; } protected Object clone() { return new Entry<K,V>(hash, key, value, (next==null ? null : (Entry<K,V>) next.clone())); } public K getKey() { return key; } public V getValue() { return value; } // 設置value。若value是null,則拋出異常。
        public V setValue(V value) { if (value == null) throw new NullPointerException(); V oldValue = this.value; this.value = value; return oldValue; } // 覆蓋equals()方法,判斷兩個Entry是否相等。 // 若兩個Entry的key和value都相等,則認為它們相等。
        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 ^ (value==null ? 0 : value.hashCode()); } public String toString() { return key.toString()+"="+value.toString(); } } private static final int KEYS = 0; private static final int VALUES = 1; private static final int ENTRIES = 2; // Enumerator的作用是提供了“通過elements()遍歷Hashtable的接口” 和 “通過entrySet()遍歷Hashtable的接口”。因為,它同時實現了 “Enumerator接口”和“Iterator接口”。
    private class Enumerator<T> implements Enumeration<T>, Iterator<T> { // 指向Hashtable的table
        Entry[] table = Hashtable.this.table; // Hashtable的總的大小
        int index = table.length; Entry<K,V> entry = null; Entry<K,V> lastReturned = null; int type; // Enumerator是 “迭代器(Iterator)” 還是 “枚舉類(Enumeration)”的標志 // iterator為true,表示它是迭代器;否則,是枚舉類。
        boolean iterator; // 在將Enumerator當作迭代器使用時會用到,用來實現fail-fast機制。
        protected int expectedModCount = modCount; Enumerator(int type, boolean iterator) { this.type = type; this.iterator = iterator; } // 從遍歷table的數組的末尾向前查找,直到找到不為null的Entry。
        public boolean hasMoreElements() { Entry<K,V> e = entry; int i = index; Entry[] t = table; /* Use locals for faster loop iteration */
            while (e == null && i > 0) { e = t[--i]; } entry = e; index = i; return e != null; } // 獲取下一個元素 // 注意:從hasMoreElements() 和nextElement() 可以看出“Hashtable的elements()遍歷方式” // 首先,從后向前的遍歷table數組。table數組的每個節點都是一個單向鏈表(Entry)。 // 然后,依次向后遍歷單向鏈表Entry。
        public T nextElement() { Entry<K,V> et = entry; int i = index; Entry[] t = table; /* Use locals for faster loop iteration */
            while (et == null && i > 0) { et = t[--i]; } entry = et; index = i; if (et != null) { Entry<K,V> e = lastReturned = entry; entry = e.next; return type == KEYS ? (T)e.key : (type == VALUES ? (T)e.value : (T)e); } throw new NoSuchElementException("Hashtable Enumerator"); } // 迭代器Iterator的判斷是否存在下一個元素 // 實際上,它是調用的hasMoreElements()
        public boolean hasNext() { return hasMoreElements(); } // 迭代器獲取下一個元素 // 實際上,它是調用的nextElement()
        public T next() { if (modCount != expectedModCount) throw new ConcurrentModificationException(); return nextElement(); } // 迭代器的remove()接口。 // 首先,它在table數組中找出要刪除元素所在的Entry, // 然后,刪除單向鏈表Entry中的元素。
        public void remove() { if (!iterator) throw new UnsupportedOperationException(); if (lastReturned == null) throw new IllegalStateException("Hashtable Enumerator"); if (modCount != expectedModCount) throw new ConcurrentModificationException(); synchronized(Hashtable.this) { Entry[] tab = Hashtable.this.table; int index = (lastReturned.hash & 0x7FFFFFFF) % tab.length; for (Entry<K,V> e = tab[index], prev = null; e != null; prev = e, e = e.next) { if (e == lastReturned) { modCount++; expectedModCount++; if (prev == null) tab[index] = e.next; else prev.next = e.next; count--; lastReturned = null; return; } } throw new ConcurrentModificationException(); } } } private static Enumeration emptyEnumerator = new EmptyEnumerator(); private static Iterator emptyIterator = new EmptyIterator(); // 空枚舉類 // 當Hashtable的實際大小為0;此時,又要通過Enumeration遍歷Hashtable時,返回的是“空枚舉類”的對象。
    private static class EmptyEnumerator implements Enumeration<Object> { EmptyEnumerator() { } // 空枚舉類的hasMoreElements() 始終返回false
        public boolean hasMoreElements() { return false; } // 空枚舉類的nextElement() 拋出異常
        public Object nextElement() { throw new NoSuchElementException("Hashtable Enumerator"); } } // 空迭代器 // 當Hashtable的實際大小為0;此時,又要通過迭代器遍歷Hashtable時,返回的是“空迭代器”的對象。
    private static class EmptyIterator implements Iterator<Object> { EmptyIterator() { } public boolean hasNext() { return false; } public Object next() { throw new NoSuchElementException("Hashtable Iterator"); } public void remove() { throw new IllegalStateException("Hashtable Iterator"); } } }
View Code

  說明: 在詳細介紹Hashtable的代碼之前,我們需要了解:和Hashmap一樣,Hashtable也是一個散列表,它也是通過“拉鏈法”解決哈希沖突的。
第3.1部分 Hashtable的“拉鏈法”相關內容

3.1.1數據節點Entry的數據結構

 1 private static class Entry<K,V> implements Map.Entry<K,V> {  2     // 哈希值
 3     int hash;  4  K key;  5  V value;  6     // 指向的下一個Entry,即鏈表的下一個節點
 7     Entry<K,V> next;  8 
 9     // 構造函數
10     protected Entry(int hash, K key, V value, Entry<K,V> next) { 11         this.hash = hash; 12         this.key = key; 13         this.value = value; 14         this.next = next; 15  } 16 
17     protected Object clone() { 18         return new Entry<K,V>(hash, key, value, 19               (next==null ? null : (Entry<K,V>) next.clone())); 20  } 21 
22     public K getKey() { 23         return key; 24  } 25 
26     public V getValue() { 27         return value; 28  } 29 
30     // 設置value。若value是null,則拋出異常。
31     public V setValue(V value) { 32         if (value == null) 33             throw new NullPointerException(); 34 
35         V oldValue = this.value; 36         this.value = value; 37         return oldValue; 38  } 39 
40     // 覆蓋equals()方法,判斷兩個Entry是否相等。 41     // 若兩個Entry的key和value都相等,則認為它們相等。
42     public boolean equals(Object o) { 43         if (!(o instanceof Map.Entry)) 44             return false; 45         Map.Entry e = (Map.Entry)o; 46 
47         return (key==null ? e.getKey()==null : key.equals(e.getKey())) &&
48            (value==null ? e.getValue()==null : value.equals(e.getValue())); 49  } 50 
51     public int hashCode() { 52         return hash ^ (value==null ? 0 : value.hashCode()); 53  } 54 
55     public String toString() { 56         return key.toString()+"="+value.toString(); 57  } 58 }
View Code

  從中,我們可以看出Entry實際上就是一個單向鏈表。這也是為什么我們說Hashtable是通過拉鏈法解決哈希沖突的。Entry 實現了Map.Entry 接口,即實現getKey(), getValue(), setValue(V value), equals(Object o), hashCode()這些函數。這些都是基本的讀取/修改key、value值的函數。

第3.2部分 Hashtable的構造函數

 1 // 默認構造函數。
 2 public Hashtable() {  3     // 默認構造函數,指定的容量大小是11;加載因子是0.75
 4     this(11, 0.75f);  5 }  6 
 7 // 指定“容量大小”的構造函數
 8 public Hashtable(int initialCapacity) {  9     this(initialCapacity, 0.75f); 10 } 11 
12 // 指定“容量大小”和“加載因子”的構造函數
13 public Hashtable(int initialCapacity, float loadFactor) { 14     if (initialCapacity < 0) 15         throw new IllegalArgumentException("Illegal Capacity: "+ initialCapacity); 16     if (loadFactor <= 0 || Float.isNaN(loadFactor)) 17         throw new IllegalArgumentException("Illegal Load: "+loadFactor); 18 
19     if (initialCapacity==0) 20         initialCapacity = 1; 21     this.loadFactor = loadFactor; 22     table = new Entry[initialCapacity]; 23     threshold = (int)(initialCapacity * loadFactor); 24 } 25 
26 // 包含“子Map”的構造函數
27 public Hashtable(Map<? extends K, ? extends V> t) { 28     this(Math.max(2*t.size(), 11), 0.75f); 29     // 將“子Map”的全部元素都添加到Hashtable中
30  putAll(t); 31 }
View Code

第3.3部分 Hashtable的主要對外接口

  3.3.1 clear()

  clear() 的作用是清空Hashtable。它是將Hashtable的table數組的值全部設為null

1 public synchronized void clear() { 2     Entry tab[] = table; 3     modCount++; 4     for (int index = tab.length; --index >= 0; ) 5         tab[index] = null; 6     count = 0; 7 }
View Code

  3.3.2 contains() 和 containsValue()

  contains() 和 containsValue() 的作用都是判斷Hashtable是否包含"值(value)"

 1 public boolean containsValue(Object value) {  2     return contains(value);  3 }  4 
 5 public synchronized boolean contains(Object value) {  6     // Hashtable中“鍵值對”的value不能是null,  7     // 若是null的話,拋出異常!
 8     if (value == null) {  9         throw new NullPointerException(); 10  } 11 
12     // 從后向前遍歷table數組中的元素(Entry) 13     // 對於每個Entry(單向鏈表),逐個遍歷,判斷節點的值是否等於value
14     Entry tab[] = table; 15     for (int i = tab.length ; i-- > 0 ;) { 16         for (Entry<K,V> e = tab[i] ; e != null ; e = e.next) { 17             if (e.value.equals(value)) { 18                 return true; 19  } 20  } 21  } 22     return false; 23 }
View Code

  3.3.3 containsKey()

  containsKey() 的作用是判斷Hashtable是否包含key

 1 public synchronized boolean containsKey(Object key) {  2     Entry tab[] = table;  3     int hash = key.hashCode();  4     // 計算索引值,  5     // % tab.length 的目的是防止數據越界
 6     int index = (hash & 0x7FFFFFFF) % tab.length;  7     // 找到“key對應的Entry(鏈表)”,然后在鏈表中找出“哈希值”和“鍵值”與key都相等的元素
 8     for (Entry<K,V> e = tab[index] ; e != null ; e = e.next) {  9         if ((e.hash == hash) && e.key.equals(key)) { 10             return true; 11  } 12  } 13     return false; 14 }
View Code

  3.3.4 elements()

  elements() 的作用是返回“所有value”的枚舉對象

 1 public synchronized Enumeration<V> elements() {  2     return this.<V>getEnumeration(VALUES);  3 }  4 
 5 // 獲取Hashtable的枚舉類對象
 6 private <T> Enumeration<T> getEnumeration(int type) {  7     if (count == 0) {  8         return (Enumeration<T>)emptyEnumerator;  9     } else { 10         return new Enumerator<T>(type, false); 11  } 12 }
View Code

  從中,我們可以看出:
  (01) 若Hashtable的實際大小為0,則返回“空枚舉類”對象emptyEnumerator;
  (02) 否則,返回正常的Enumerator的對象。(Enumerator實現了迭代器和枚舉兩個接口)

  我們先看看emptyEnumerator對象是如何實現的

 1 private static Enumeration emptyEnumerator = new EmptyEnumerator();  2 //空枚舉類  3 //當Hashtable的實際大小為0;此時,又要通過Enumeration遍歷Hashtable時,返回的是“空枚舉類”的對象。
 4 private static class EmptyEnumerator implements Enumeration<Object> {  5  EmptyEnumerator() {  6  }  7     // 空枚舉類的hasMoreElements() 始終返回false
 8     public boolean hasMoreElements() {  9         return false; 10  } 11     // 空枚舉類的nextElement() 拋出異常
12     public Object nextElement() { 13         throw new NoSuchElementException("Hashtable Enumerator"); 14  } 15 }
View Code

  我們在來看看Enumeration類Enumerator的作用是提供了“通過elements()遍歷Hashtable的接口”和“通過entrySet()遍歷Hashtable的接口”。因為,它同時實現了 “Enumerator接口”和“Iterator接口”。

 1 private class Enumerator<T> implements Enumeration<T>,Iterator<T>{  2     // 指向Hashtable的table
 3     Entry[] table = Hashtable.this.table;  4     //Hashtable的總的大小
 5     int index = table.length;  6     Entry<K,V> entry = null;  7     Entry<K,V> lastReturned = null;  8     int type;  9     //Enumerator是 “迭代器(Iterator)” 還是 “枚舉類(Enumeration)”的標志 10     //iterator為true,表示它是迭代器;否則,是枚舉類。
11     boolean iterator; 12     // 在將Enumerator當作迭代器使用時會用到,用來實現fail-fast機制。
13     protected int expectedModCount = modCount; 14     Enumerator(int type, boolean iterator) { 15         this.type = type; 16         this.iterator = iterator; 17  } 18     //從遍歷table的數組的末尾向前查找,直到找到不為null的Entry。
19     public boolean hasMoreElements() { 20         Entry<K,V> e = entry; 21         int i = index; 22         Entry[] t = table; 23         /* Use locals for faster loop iteration */
24         while (e == null && i > 0) { 25             e = t[--i]; 26  } 27         entry = e; 28         index = i; 29         return e != null; 30  } 31 
32     //獲取下一個元素 33     //注意:從hasMoreElements() 和nextElement() 可以看出“Hashtable的elements()遍歷方式” 34     //首先,從后向前的遍歷table數組。table數組的每個節點都是一個單向鏈表(Entry)。 35     //然后,依次向后遍歷單向鏈表Entry。
36     public T nextElement() { 37         Entry<K,V> et = entry; 38         int i = index; 39         Entry[] t = table; 40         /* Use locals for faster loop iteration */
41         while (et == null && i > 0) { 42             et = t[--i]; 43  } 44         entry = et; 45         index = i; 46         if (et != null) { 47             Entry<K,V> e = lastReturned = entry; 48             entry = e.next; 49             return type == KEYS ? (T)e.key : (type == VALUES ? (T)e.value : (T)e); 50  } 51         throw new NoSuchElementException("Hashtable Enumerator"); 52  } 53 
54     //迭代器Iterator的判斷是否存在下一個元素 55     //實際上,它是調用的hasMoreElements()
56     public boolean hasNext() { 57         return hasMoreElements(); 58  } 59 
60     //迭代器獲取下一個元素 61     //實際上,它是調用的nextElement()
62     public T next() { 63         if (modCount != expectedModCount) 64             throw new ConcurrentModificationException(); 65         return nextElement(); 66  } 67 
68     //迭代器的remove()接口。 69     //首先,它在table數組中找出要刪除元素所在的Entry, 70     //然后,刪除單向鏈表Entry中的元素。
71     public void remove() { 72         if (!iterator) 73             throw new UnsupportedOperationException(); 74         if (lastReturned == null) 75             throw new IllegalStateException("Hashtable Enumerator"); 76         if (modCount != expectedModCount) 77             throw new ConcurrentModificationException(); 78         synchronized(Hashtable.this) { 79             Entry[] tab = Hashtable.this.table; 80             int index = (lastReturned.hash & 0x7FFFFFFF) % tab.length; 81 
82             for (Entry<K,V> e = tab[index], prev = null; e != null; 83                  prev = e, e = e.next) { 84                 if (e == lastReturned) { 85                     modCount++; 86                     expectedModCount++; 87                     if (prev == null) 88                         tab[index] = e.next; 89                     else
90                         prev.next = e.next; 91                     count--; 92                     lastReturned = null; 93                     return; 94  } 95  } 96             throw new ConcurrentModificationException(); 97  } 98  } 99 }
View Code

  entrySet(), keySet(), keys(), values()的實現方法和elements()差不多,而且源碼中已經明確的給出了注釋。這里就不再做過多說明了。

  3.3.5 get()

  get() 的作用就是獲取key對應的value,沒有的話返回null

 1 public synchronized V get(Object key) { 2     Entry tab[] = table; 3     int hash = key.hashCode(); 4     // 計算索引值,
 5     int index = (hash & 0x7FFFFFFF) % tab.length; 6     // 找到“key對應的Entry(鏈表)”,然后在鏈表中找出“哈希值”和“鍵值”與key都相等的元素
 7     for (Entry<K,V> e = tab[index] ; e != null ; e = e.next) { 8         if ((e.hash == hash) && e.key.equals(key)) { 9             return e.value; 10 } 11 } 12     return null; 13 }
View Code

  3.3.6 put()

  put() 的作用是對外提供接口,讓Hashtable對象可以通過put()將“key-value”添加到Hashtable中。

 1 public synchronized V put(K key, V value) { 2     // Hashtable中不能插入value為null的元素!!!
 3     if (value == null) { 4         throw new NullPointerException(); 5 } 7     // 若“Hashtable中已存在鍵為key的鍵值對”,
 8     // 則用“新的value”替換“舊的value”
 9     Entry tab[] = table; 10     int hash = key.hashCode(); 11     int index = (hash & 0x7FFFFFFF) % tab.length; 12     for (Entry<K,V> e = tab[index] ; e != null ; e = e.next) { 13         if ((e.hash == hash) && e.key.equals(key)) { 14             V old = e.value; 15             e.value = value; 16             return old; 17 } 18 } 20     // 若“Hashtable中不存在鍵為key的鍵值對”,
21     // (01) 將“修改統計數”+1
22     modCount++; 23     // (02) 若“Hashtable實際容量” > “閾值”(閾值=總的容量 * 加載因子)
24     // 則調整Hashtable的大小
25     if (count >= threshold) { 26         // Rehash the table if the threshold is exceeded
27 rehash(); 28 
29         tab = table; 30         index = (hash & 0x7FFFFFFF) % tab.length; 31 } 32 
33     // (03) 將“Hashtable中index”位置的Entry(鏈表)保存到e中
34     Entry<K,V> e = tab[index]; 35     //(04) 創建“新的Entry節點”,並將“新的Entry”插入“Hashtable的index位、置”,並設置e為“新的Entry”的下一個元素(即“新Entry”為鏈表表頭)。 
36     tab[index] = new Entry<K,V>(hash, key, value, e); 37     // (05) 將“Hashtable的實際容量”+1
38     count++; 39     return null; 40 }
View Code

  3.3.7 putAll()

  putAll() 的作用是將“Map(t)”的中全部元素逐一添加到Hashtable中

1 public synchronized void putAll(Map<? extends K, ? extends V> t) { 2     for (Map.Entry<? extends K, ? extends V> e : t.entrySet()) 3 put(e.getKey(), e.getValue()); 4 }
View Code

  3.3.8 remove()

  remove() 的作用就是刪除Hashtable中鍵為key的元素

 1 public synchronized V remove(Object key) {  2     Entry tab[] = table;  3     int hash = key.hashCode();  4     int index = (hash & 0x7FFFFFFF) % tab.length;  5     // 找到“key對應的Entry(鏈表)”  6     // 然后在鏈表中找出要刪除的節點,並刪除該節點。
 7     for (Entry<K,V> e = tab[index],prev=null ; e!=null;prev=e,e= e.next) {  8         if ((e.hash == hash) && e.key.equals(key)) {  9             modCount++; 10             if (prev != null) { 11                 prev.next = e.next; 12             } else { 13                 tab[index] = e.next; 14  } 15             count--; 16             V oldValue = e.value; 17             e.value = null; 18             return oldValue; 19  } 20  } 21     return null; 22 }
View Code

第3.4部分 Hashtable實現的Cloneable接口

  Hashtable實現了Cloneable接口,即實現了clone()方法。
  clone()方法的作用很簡單,就是克隆一個Hashtable對象並返回。

 1 // 克隆一個Hashtable,並以Object的形式返回。
 2 public synchronized Object clone() {  3     try {  4         Hashtable<K,V> t = (Hashtable<K,V>) super.clone();  5         t.table = new Entry[table.length];  6         for (int i = table.length ; i-- > 0 ; ) {  7             t.table[i] = (table[i] != null)  8             ? (Entry<K,V>) table[i].clone() : null;  9  } 10         t.keySet = null; 11         t.entrySet = null; 12         t.values = null; 13         t.modCount = 0; 14         return t; 15     } catch (CloneNotSupportedException e) { 16         // this shouldn't happen, since we are Cloneable
17         throw new InternalError(); 18  } 19 }
View Code

第3.5部分 Hashtable實現的Serializable接口

  Hashtable實現java.io.Serializable,分別實現了串行讀取、寫入功能。串行寫入函數就是將Hashtable的“總的容量,實際容量,所有的Entry”都寫入到輸出流中.串行讀取函數:根據寫入方式讀出將Hashtable的“總的容量,實際容量,所有的Entry”依次讀出

private synchronized void writeObject(java.io.ObjectOutputStream s)
    throws IOException
{
    // Write out the length, threshold, loadfactor
    s.defaultWriteObject();

    // Write out length, count of elements and then the key/value objects
    s.writeInt(table.length);
    s.writeInt(count);
    for (int index = table.length-1; index >= 0; index--) {
        Entry entry = table[index];

        while (entry != null) {
        s.writeObject(entry.key);
        s.writeObject(entry.value);
        entry = entry.next;
        }
    }
}

private void readObject(java.io.ObjectInputStream s)
     throws IOException, ClassNotFoundException
{
    // Read in the length, threshold, and loadfactor
    s.defaultReadObject();

    // Read the original length of the array and number of elements
    int origlength = s.readInt();
    int elements = s.readInt();

    // Compute new size with a bit of room 5% to grow but
    // no larger than the original size.  Make the length
    // odd if it's large enough, this helps distribute the entries.
    // Guard against the length ending up zero, that's not valid.
    int length = (int)(elements * loadFactor) + (elements / 20) + 3;
    if (length > elements && (length & 1) == 0)
        length--;
    if (origlength > 0 && length > origlength)
        length = origlength;

    Entry[] table = new Entry[length];
    count = 0;

    // Read the number of elements and then all the key/value objects
    for (; elements > 0; elements--) {
        K key = (K)s.readObject();
        V value = (V)s.readObject();
            // synch could be eliminated for performance
            reconstitutionPut(table, key, value);
    }
    this.table = table;
}
View Code

第4部分 Hashtable遍歷方式

  4.1 遍歷Hashtable的鍵值對

  第一步:根據entrySet()獲取Hashtable的“鍵值對”的Set集合。
  第二步:通過Iterator迭代器遍歷“第一步”得到的集合。

 1 // 假設table是Hashtable對象  2 // table中的key是String類型,value是Integer類型
 3 Integer integ = null;  4 Iterator iter = table.entrySet().iterator();  5 while(iter.hasNext()) {  6     Map.Entry entry = (Map.Entry)iter.next();  7     // 獲取key
 8     key = (String)entry.getKey();  9         // 獲取value
10     integ = (Integer)entry.getValue(); 11 }
View Code

4.2 通過Iterator遍歷Hashtable的鍵

  第一步:根據keySet()獲取Hashtable的“鍵”的Set集合。
  第二步:通過Iterator迭代器遍歷“第一步”得到的集合。

 1 //假設table是Hashtable對象  2 //table中的key是String類型,value是Integer類型
 3 String key = null;  4 Integer integ = null;  5 Iterator iter = table.keySet().iterator();  6 while (iter.hasNext()) {  7         // 獲取key
 8     key = (String)iter.next();  9         // 根據key,獲取value
10     integ = (Integer)table.get(key); 11 }
View Code

4.3 通過Iterator遍歷Hashtable的值

  第一步:根據value()獲取Hashtable的“值”的集合。
  第二步:通過Iterator迭代器遍歷“第一步”得到的集合。

1 // 假設table是Hashtable對象 2 // table中的key是String類型,value是Integer類型
3 Integer value = null; 4 Collection c = table.values(); 5 Iterator iter= c.iterator(); 6 while (iter.hasNext()) { 7     value = (Integer)iter.next(); 8 }
View Code

4.4 通過Enumeration遍歷Hashtable的鍵

  第一步:根據keys()獲取Hashtable的集合。
  第二步:通過Enumeration遍歷“第一步”得到的集合。

1 Enumeration enu = table.keys(); 2 while(enu.hasMoreElements()) { 3  System.out.println(enu.nextElement()); 4 } 
View Code

4.5 通過Enumeration遍歷Hashtable的值

  第一步:根據elements()獲取Hashtable的集合。
  第二步:通過Enumeration遍歷“第一步”得到的集合。

1 Enumeration enu = table.keys(); 2 while(enu.hasMoreElements()) { 3  System.out.println(enu.nextElement()); 4 }   
View Code


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM