HashMap到底是插入鍊錶頭部還是尾部

2021-08-18 18:25:19 字數 2596 閱讀 8623

同學去面試京東,被問了乙個問題:我們都知道,hashmap是由entry鍊錶組成的陣列,當hashmap要在煉表裡插入新的entry時,到底是插入頭部還是尾部呢?我通過檢視自己電腦上的jdk1.8的原始碼,發現是插入尾部的,但是我同學告訴我面試官告訴他答案是插入頭部,這篇文章就從原始碼角度一**竟。

在jdk1.8之前是插入頭部的,在jdk1.8中是插入尾部的。

分析鍊錶插入的位置,重點是分析hashmap的put方法。

put方法的**如下:

public v put(k key, v value) 

}//如果遍歷鍊錶沒發現這個key,則會呼叫以下**

modcount++;

addentry(hash, key, value, i);

return

null;

}

閱讀原始碼發現,如果遍歷鍊錶都沒法發現相應的key值的話,則會呼叫addentry方法在鍊錶新增乙個entry,重點就在與addentry方法是如何插入鍊錶的,addentry方法原始碼如下:

void addentry(int hash, k key, v value, int bucketindex)
這裡構造了乙個新的entry物件(構造方法的最後乙個引數傳入了當前的entry鍊錶),然後直接用這個新的entry物件取代了舊的entry鍊錶,可以猜測這應該是頭插法,為了進一步確認這個想法,我們再看一下entry的構造方法:

entry( int h, k k, v v, entry n)
從構造方法中的nexrt=n可以看出確實是把原本的鍊錶直接鏈在了新建的entry物件的後邊,可以斷定是插入頭部。

put方法的**如下:

public v put(k key, v value)
繼續進入putval方法(先不要著急去讀它):

/**

* implements map.put and related methods

* *@param hash hash for key

*@param key the key

*@param value the value to put

*@param onlyifabsent if true, don't change existing value

*@param evict if false, the table is in creation mode.

*@return previous value, or null if none

*/final v putval(int hash, k key, v value, boolean onlyifabsent,

boolean evict)

if (e.hash == hash &&

((k = e.key) == key || (key != null && key.equals(k))))

break;

p = e;}}

v oldvalue = e.value;

if (!onlyifabsent || oldvalue == null)

e.value = value;

afternodeaccess(e);

return oldvalue;}}

++modcount;

if (++size > threshold)

resize();

afternodeinsertion(evict);

return

null;

}

for (int bincount = 0; ; ++bincount) 

//如果key在鍊錶中已經存在,則退出迴圈

if (e.hash == hash &&

((k = e.key) == key || (key != null && key.equals(k))))

break;

p = e;

}//如果key在鍊錶中已經存在,則修改其原先的key值,並且返回老的值

v oldvalue = e.value;

if (!onlyifabsent || oldvalue == null)

e.value = value;

afternodeaccess(e);

return oldvalue;

}

**我一行行加了注釋,其中鍊錶插入的**是:

//e是p的下乙個節點

if ((e = p.next) == null)

從這段**中可以很顯然地看出當到達鍊錶尾部(即p是鍊錶的最後乙個節點)時,e被賦為null,會進入這個分支**,然後會用newnode方法建立乙個新的節點插入尾部。

結論:jdk1.8中是插入的是鍊錶尾部

在原始碼中注意到一些其他有趣的地方。

在jdk1.6中,hashmap中有個內建entry類,它實現了map.entry介面;而在jdk1.8中,這個entry類不見了,變成了node類,也實現了map.entry介面,與jdk1.6中的entry是等價的。

this到底是誰

js中函式的4種呼叫方式 1.作為普通函式來呼叫 alert window.xx undefined function t t alert window.xx 333 解釋 作為普通函式來呼叫this時,this的值指向 windwo,準確的說,this為null,但被解釋成window,在ecma...

Segmentation fault到底是何方妖孽

那麼對於任何沒有經過 mmu對映過的虛擬空間的位址,不管程序是執行寫操作還是讀操作,作業系統都會捕捉到這個錯誤的非法訪問,然後輸出乙個 segmetation fault 的錯誤提示資訊並強行終止程序。程式之所以會時不時的出現 segmetation fault 的根本原因是程序訪問到了沒有訪問許可...

鍊錶你到底是幹啥的?

鍊錶這個逗逼 我暫時還沒能完整的了解它 只是簡單的搞了個單鏈表 單鏈表 的好處還待挖掘 但是 單鏈表的脾氣我摸清了 首先 它是個類 裡面的 屬性 是 一些叫做 節點的類 這個節點類是重點 它裡面有 乙個 權值100分 基本資料型別 int double 啥的 以及 乙個 其他鍊錶是 多個 這個一切從...