JDK源碼學習09----HashTable
1.HashTable簡介
Hashtable 也是一個散列表,它存儲的內容是鍵值對(key-value)映射。
Hashtable 繼承於Dictionary,實現了Map、Cloneable、java.io.Serializable接口。
Hashtable 的函數都是同步的,這意味着它是線程安全的。它的key、value都不可以爲null。此外,Hashtable中的映射不是有序的。
public class Hashtable<K,V> extends Dictionary<K,V>
implements Map<K,V>, Cloneable, java.io.Serializable { }
2.HashTable的成員變量
// 默認構造函數。
public Hashtable()
// 指定“容量大小”的構造函數
public Hashtable(int initialCapacity)
// 指定“容量大小”和“加載因子”的構造函數
public Hashtable(int initialCapacity, float loadFactor)
// 包含“子Map”的構造函數
public Hashtable(Map<? extends K, ? extends V> t)
它包括幾個重要的成員變量:table, count, threshold, loadFactor, modCount。table是一個Entry[]數組類型,而Entry實際上就是一個單向鏈表。哈希表的"key-value鍵值對"都是存儲在Entry數組中的。
count是Hashtable的大小,它是Hashtable保存的鍵值對的數量。
threshold是Hashtable的閾值,用於判斷是否需要調整Hashtable的容量。threshold的值="容量*加載因子"。
loadFactor就是加載因子。
modCount是用來實現fail-fast機制的
3.HashTable 的構造函數
// 默認構造函數。
public Hashtable() {
// 默認構造函數,指定的容量大小是11;加載因子是0.75
this(11, 0.75f);
}
// 指定“容量大小”的構造函數
public Hashtable(int initialCapacity) {
this(initialCapacity, 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;
table = new Entry[initialCapacity];
threshold = (int)(initialCapacity * loadFactor);
}
// 包含“子Map”的構造函數
public Hashtable(Map<? extends K, ? extends V> t) {
this(Math.max(2*t.size(), 11), 0.75f);
// 將“子Map”的全部元素都添加到Hashtable中
putAll(t);
}
4.HashTable常用方法
4.1V put(K key, V value)
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; }
4.2 V get(Object key)
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;
}
4.3 clear()
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 }
4.4contains() 和 containsValue()
public boolean containsValue(Object value) {
return contains(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;
}
4.5void putAll(Map<? extends K, ? extends V> t)
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());
}
4.6 V remove(Object 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;
}
5.HashMap的數據節點Entry<K,V>類
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();
}
}
6.總結
a.HashTable 是同步的,線程安全,適合多線程。
b.HashTable的鍵值都 不能 爲null.
c.HashTable和HashMap一樣,也是通過拉鍊法解決hash衝突的。