文章均爲本人技術筆記,轉載請註明出處https://segmentfault.com/u/yzwalljava
public class Hashtable<K,V> extends Dictionary<K,V> implements Map<K,V>, Cloneable, java.io.Serializablesegmentfault
Hashtable和HashMap同樣也是散列表,存儲元素也是鍵值對;
Hashtable繼承於Dictionary類(Dictionary類聲明瞭操做鍵值對的接口方法),實現Map接口(定義鍵值對接口);
Hashtable大部分類用synchronized
修飾,證實Hashtable是線程安全的;數組
private transient Entry<?,?>[] table
:鍵值對/Entry數組,每一個Entry本質上是一個單向鏈表的表頭安全
private int threshold
:rehash閾值數據結構
private float loadFactor
:裝填因子函數
private transient int modCount = 0
: Hashtable結構化修改次數,用來實現fail-fast機制;線程
private transient volatile Set<Map.Entry<K,V>> entrySet
:Hastable視圖,鍵值對集合;code
private transient volatile Set<K> keySet
:Hastable視圖,key集,Hashtable中key不可重複;繼承
private transient volatile Collection<V> values
:Hastable視圖,value集合,可重複;索引
Hashtable中key和value是一對多關係;
private static class Entry<K,V> implements Map.Entry<K,V> { final int hash; final K key; V value; Entry<K, V> next; ... // 計算鍵值對的hashCode public int hashCode() { // "^" 按位異或, hash在調用構造器時傳入 return hash ^ Objects.hashCode(value); } }
鍵值對
public boolean containsValue(Object value)
內部調用contains(value)
;
判斷是否含有該value的鍵值對,在Hashtable中hashCode相同的Entry用鏈表組織,hashCode不一樣的存儲在Entry數組table中;
// in contains() method. Entry<?,?> tab[] = table; // 查找:遍歷全部Entry鏈表 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;
int index = (hash & 0x7FFFFFFF) % tab.length;
計算鍵值對的桶位(本質是鍵值對在tab數組中的索引),Hashtable本質上採用除數取餘法進行散列分佈,模運算效率較低
int hash = key.hashCode()
Hashtable直接調用key的hashCode()計算hashCode;
Entry<?,?> tab[] = table; int hash = key.hashCode(); /** * 計算index, % tab.length防止數組越界 * index表示key對應entry所在鏈表表頭 */ 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;
public synchronized V get(Object key)
:根據指定key查找對應value,查找原理與containsKey相同,查找成功返回value,不然返回null;
設置鍵值對,key和value都不可爲null,設置順序:
若是Hashtable含有key,設置(key, oldValue) -> (key, newValue);
若是Hashtable不含有key, 調用addEntry(...)
添加新的鍵值對;
當鍵值對個數超過閾值,先進行rehash而後添加entry,不然直接添加entry;
remove操做,計算key所在鏈表表頭table[index],而後進行單向鏈表的節點刪除操做
對Hashtable的淺拷貝操做,淺拷貝全部bucket(單向鏈表組織形式)的表頭;
當Hashtable中鍵值對總數超過閾值(容量*裝載因子)後,內部自動調用rehash()增長容量,從新計算每一個鍵值對的hashCode;int newCapacity = (oldCapacity << 1) + 1
計算新容量 = 2 * 舊容量 + 1;而且根據新容量更新閾值;
... for (int i = oldCapacity ; i-- > 0 ;) { // 拷貝每一個Entry鏈表 for (Entry<K,V> old = (Entry<K,V>)oldMap[i] ; old != null ; ) { Entry<K,V> e = old; old = old.next; // 從新計算每一個Entry鏈表的表頭索引(rehash) int index = (e.hash & 0x7FFFFFFF) % newCapacity; // 開闢鏈表節點 e.next = (Entry<K,V>)newMap[index]; // 拷貝 newMap[index] = e; } }