同學去面試京東,被問了乙個問題:我們都知道,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 啥的 以及 乙個 其他鍊錶是 多個 這個一切從...