注:本文基於jdk1.8
hashtable與hashmap相同,都是使用雜湊表來實現儲存結構,在功能上,他們兩也基本相同,除了hashmap可以使用null的鍵值對和hashtable是執行緒安全的。
雜湊表的結構在jdk1.8之後略有不同,hashmap採用了鍊錶+紅黑樹的方式來解決hash衝突,但hashtable仍只使用鍊錶來解決。
hashtable所繼承的類與hashmap不同,它是繼承於dictionary類,這是乙個已經廢棄的類,不建議使用。當然,hashmap和hashtable都實現了map介面。
類的繼承關係:
hashtable的主要成員變數:
//hash表
private transient entry<?,?> table;
//鍵值對的數量(注意不是hash表的長度)
private transient int count;
//載入閾值
private int threshold;
//載入因子
private float loadfactor;
//表結構變化次數,用於快速失敗
private transient int modcount = 0;
構造方法:
hashtable的構造方法與hashmap基本相同,但是無參的構造方法的預設配置不同:
public hashtable()
hashmap的預設大小為16,使用default_initial_capacity儲存;而hashtable的預設大小為11,且是硬編碼的。
重要方法:
public synchronized v put(k key, v value)
// makes sure the key is not already in the hashtable.
entry<?,?> tab = table;
//計算key的hash碼。
int hash = key.hashcode();
//根據hash碼計算儲存位置
int index = (hash & 0x7fffffff) % tab.length;
@suppresswarnings("unchecked")
entryentry = (entry)tab[index];
for(; entry != null ; entry = entry.next)
}//執行新增操作
addentry(hash, key, value, index);
return null;
}
在put方法中只對value為null進行了處理,對key為null的處理實際上在object的hashcode方法中,這是乙個native方法,會對null值丟擲異常。
private void addentry(int hash, k key, v value, int index)
@suppresswarnings("unchecked")
entrye = (entry) tab[index];
//注意,原來的鍊錶e放在了新鍊錶的後頭,也就是說新節點總是插入在鍊錶的頭部
tab[index] = new entry<>(hash, key, value, e);
//鍵值對數量增加
count++;
}
addentity方法總是將新加入的節點放置在鍊錶的頭部,在jdk1.7中hashmap也是這樣,但是在jdk1.8中hashmap則會將新節點放置在鍊錶的尾部。
protected void rehash()
entry<?,?> newmap = new entry<?,?>[newcapacity];
modcount++;
//計算新的載入閾值
threshold = (int)math.min(newcapacity * loadfactor, max_array_size + 1);
table = newmap;
//將老元素一一重新計算hash放置在新hash表中
for (int i = oldcapacity ; i-- > 0 ;)
}}
rehash操作對容量的變化與hashmap不同,hashmap總是變為原來的兩邊且保證為2的次冪,而hashtable為原來的兩倍加一,保證為質數。這是因為他們的計算陣列下標的方式不同導致的。
hashmap計算元素位置的方式為 hashcode&(length-1) ,hash碼與長度減一進行與操作,當length為2的次冪時,length-1總為011**111形式,這樣在與操作時都為自己本身,操作較快,且當出現某一位為0時,任何數隻在該位不同的數操作的結果都是相同的,這大大增加了hash碰撞的機率,因此hashmap要求容量為2的次冪。
hashtable計算元素位置的方式為(hash & 0x7fffffff) % tab.length,由於存在一部取餘操作,所以當hash的低位相同高位不同時會很容易因為高位失效出現hash衝突,因此要求為質數。
public synchronized v remove(object key) else
count--;
v oldvalue = e.value;
e.value = null;
return oldvalue;}}
return null;
}
remove方法比較簡單,找到對應的鍊錶挨個查詢將其除掉。
public synchronized object clone()
t.keyset = null;
t.entryset = null;
t.values = null;
t.modcount = 0;
return t;
} catch (clonenotsupportedexception e)
}
hashtable的轉殖方法為淺度轉殖,僅僅轉殖了結構並沒有複製鍵值對,而是在轉殖的物件中儲存了乙個鍵值對的位址,要實現深度轉殖需要重寫此方法。
hashtable的主要方法就為這些,注意上面的public方法都帶有synchronized關鍵字,因此hashtable是執行緒安全的,但是這種執行緒安全的實現並不是很好,如果需要執行緒安全的類最好使用
collections.
synchronizedmap
()。
java1 8版本hashTable原始碼閱讀
注 本文基於jdk1.8 hashtable與hashmap相同,都是使用雜湊表來實現儲存結構,在功能上,他們兩也基本相同,除了hashmap可以使用null的鍵值對和hashtable是執行緒安全的。雜湊表的結構在jdk1.8之後略有不同,hashmap採用了鍊錶 紅黑樹的方式來解決hash衝突,...
java 18 異常處理
1 異常處理執行順序 當出現異常時,異常處理各部分執行順序 測試異常處理各個位置執 況 public static void textexception catch exception e finally 執行結果 設定返回值的情況 3 注釋掉finally中的return。catch中不注釋掉。測...
java18年技術要領整理
spring bean 的生命週期 spring ioc 如何實現 說說 spring aop spring aop 實現原理 動態 cglib 與 jdk spring 事務實現方式 spring 事務底層原理 如何自定義註解實現功能 spring mvc 執行流程 spring mvc 啟動流程...