java1 8版本hashTable原始碼閱讀

2021-08-07 18:28:01 字數 3376 閱讀 8582

注:本文基於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 啟動流程...