和HashMap同樣,Hashtable 也是一個散列表,它存儲的內容是鍵值對(key-value)映射。 Hashtable 繼承於Dictionary,實現了Map、Cloneable、java.io.Serializable接口。 Hashtable 的函數都是同步的,這意味着它是線程安全的。它的key、value都不能夠爲null。此外,Hashtable中的映射不是有序的。html
Hashtable 的實例有兩個參數影響其性能:初始容量 和 加載因子。容量 是哈希表中桶 的數量,初始容量 就是哈希表建立時的容量。注意,哈希表的狀態爲 open:在發生「哈希衝突」的狀況下,單個桶會存儲多個條目,這些條目必須按順序搜索。加載因子 是對哈希表在其容量自動增長以前能夠達到多滿的一個尺度。初始容量和加載因子這兩個參數只是對該實現的提示。關於什麼時候以及是否調用 rehash 方法的具體細節則依賴於該實現。 一般,默認加載因子是 0.75, 這是在時間和空間成本上尋求一種折衷。加載因子太高雖然減小了空間開銷,但同時也增長了查找某個條目的時間(在大多數 Hashtable 操做中,包括 get 和 put 操做,都反映了這一點)。java
// 默認構造函數。 public Hashtable() // 指定「容量大小」的構造函數 public Hashtable(int initialCapacity) // 指定「容量大小」和「加載因子」的構造函數 public Hashtable(int initialCapacity, float loadFactor) // 包含「子Map」的構造函數 public Hashtable(Map<? extends K, ? extends V> t)
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繼承於Dictionary類,實現了Map接口。Map是"key-value鍵值對"接口,Dictionary是聲明瞭操做"鍵值對"函數接口的抽象類。算法
Hashtable是經過"拉鍊法"實現的哈希表。它包括幾個重要的成員變量:table, count, threshold, loadFactor, modCount。數組
table是一個Entry[]數組類型,而Entry實際上就是一個單向鏈表。哈希表的"key-value鍵值對"都是存儲在Entry數組中的。安全
count是Hashtable的大小,它是Hashtable保存的鍵值對的數量。函數
threshold是Hashtable的閾值,用於判斷是否須要調整Hashtable的容量。threshold的值="容量*加載因子"。性能
loadFactor就是加載因子。this
modCount是用來實現fail-fast機制的線程
public Hashtable(int initialCapacity, float loadFactor): 用指定初始容量和指定加載因子構造一個新的空哈希表。useAltHashing 爲 boolean,其若是爲真,則執行另外一散列的字符串鍵,以減小因爲弱哈希計算致使的哈希衝突的發生。
public Hashtable(int initialCapacity):用指定初始容量和默認的加載因子 (0.75) 構造一個新的空哈希表。
public Hashtable():默認構造函數,容量爲 11,加載因子爲 0.75。
public Hashtable(Map<? extends K, ? extends V> t):構造一個與給定的 Map 具備相同映射關係的新哈希表。
public Hashtable() { this(11, 0.75f); } 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; //private transient Entry<K,V>[] table; table = new Entry[initialCapacity]; // private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8; //獲取閾值大小 threshold = (int)Math.min(initialCapacity * loadFactor, MAX_ARRAY_SIZE + 1); //初始化哈希掩碼值。 initHashSeedAsNeeded(initialCapacity); } private static class Entry<K,V> implements Map.Entry<K,V> { int hash; final K key; V value; 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<>(hash, key, value, (next==null ? null : (Entry<K,V>) 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.equals(e.getKey()) && value.equals(e.getValue()); } public int hashCode() { return (Objects.hashCode(key) ^ Objects.hashCode(value)); } public String toString() { return key.toString()+"="+value.toString(); } }
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. //確保key不在hashtable中 //首先,經過hash方法計算key的哈希值,並計算得出index值,肯定其在table[]中的位置 //其次,迭代index索引位置的鏈表,若是該位置處的鏈表存在相同的key,則替換value,返回舊的value Entry tab[] = table; int hash = hash(key); 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; } } modCount++; if (count >= threshold) { // Rehash the table if the threshold is exceeded rehash(); tab = table; hash = hash(key); index = (hash & 0x7FFFFFFF) % tab.length; } // Creates the new entry. Entry<K,V> e = tab[index]; // 建立新的Entry節點,並將新的Entry插入Hashtable的index位置,並設置e爲新的Entry的下一個元素 tab[index] = new Entry<>(hash, key, value, e); count++; return null; }
相比較於 put 方法,get 方法則簡單不少。其過程就是首先經過 hash()方法求得 key 的哈希值,而後根據 hash 值獲得 index 索引(上述兩步所用的算法與 put 方法都相同)。而後迭代鏈表,返回匹配的 key 的對應的 value;找不到則返回 null。
public synchronized V get(Object key) { Entry tab[] = table; int hash = hash(key); 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)) { return e.value; } } return null; }
public synchronized boolean isEmpty() { return count == 0; }
public synchronized void clear方法() { Entry tab[] = table; modCount++; for (int index = tab.length; --index >= 0; ) tab[index] = null; count = 0; }
public boolean containsValue(Object value) { return contains(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<K,V> e = tab[i] ; e != null ; e = e.next) { if (e.value.equals(value)) { return true; } } } return false; }
public synchronized boolean containsKey(Object key) { Entry tab[] = table; int hash = hash(key); 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)) { return true; } } return false; }
package basic; import java.util.Enumeration; import java.util.Hashtable; import java.util.Iterator; import java.util.Map; /** * @program: demo * @description: demo * @author: lee * @create: 2018-09-10 **/ public class Demo { public static void main(String[] args) { Hashtable hashtable = new Hashtable(); hashtable.put("123",31231); hashtable.put("1423",32); Enumeration<String> stringEnumeration = hashtable.keys(); while (stringEnumeration.hasMoreElements()){ String key=stringEnumeration.nextElement(); System.out.println(hashtable.get(key)); } Iterator iterator = hashtable.keySet().iterator(); while (iterator.hasNext()) { Object key = iterator.next(); System.out.println(hashtable.get(key)); } Iterator iterator1 = hashtable.entrySet().iterator(); while (iterator1.hasNext()) { Map.Entry entry = (Map.Entry) iterator1.next(); System.out.println(entry.getKey()); System.out.println(entry.getValue()); } } }
輸出結果
32 31231 32 31231 1423 32 123 31231