1、“你知道HashMap的工作原理嗎?” “你知道HashMap的get()方法的工作原理嗎?”
HashMap是基于hashing的原理,我們使用put(key, value)存儲對象到HashMap中,使用get(key)從HashMap中獲取對象。當(dāng)我們給put()方法傳遞鍵和值時,我們先對鍵調(diào)用hashCode()方法,返回的hashCode用于找到bucket位置來儲存Entry對象?!边@里關(guān)鍵點(diǎn)在于指出,HashMap是在bucket中儲存鍵對象和值對象,作為Map.Entry。
2、“當(dāng)兩個對象的hashcode相同會發(fā)生什么?”
因?yàn)閔ashcode相同,所以它們的bucket位置相同,‘碰撞’會發(fā)生。因?yàn)镠ashMap使用LinkedList存儲對象,這個Entry(包含有鍵值對的Map.Entry對象)會存儲在LinkedList中。(當(dāng)向 HashMap 中添加 key-value 對,由其 key 的 hashCode() 返回值決定該 key-value 對(就是 Entry 對象)的存儲位置。當(dāng)兩個 Entry 對象的 key 的 hashCode() 返回值相同時,將由 key 通過 eqauls() 比較值決定是采用覆蓋行為(返回 true),還是產(chǎn)生 Entry 鏈(返回 false)。)
3、“如果兩個鍵的hashcode相同,你如何獲取值對象?”
當(dāng)我們調(diào)用get()方法,HashMap會使用鍵對象的hashcode找到bucket位置,然后獲取值對象。如果有兩個值對象儲存在同一個bucket,將會遍歷LinkedList直到找到值對象。找到bucket位置之后,會調(diào)用keys.equals()方法去找到LinkedList中正確的節(jié)點(diǎn),最終找到要找的值對象。(當(dāng)程序通過 key 取出對應(yīng) value 時,系統(tǒng)只要先計(jì)算出該 key 的 hashCode() 返回值,在根據(jù)該 hashCode 返回值找出該 key 在 table 數(shù)組中的索引,然后取出該索引處的 Entry,最后返回該 key 對應(yīng)的 value 即可。)
4、“如果HashMap的大小超過了負(fù)載因子(load factor)定義的容量,怎么辦?”
當(dāng)一個map填滿了75%的bucket時候,和其它集合類(如ArrayList等)一樣,將會創(chuàng)建原來HashMap大小的兩倍的bucket數(shù)組,來重新調(diào)整map的大小,并將原來的對象放入新的bucket數(shù)組中。這個過程叫作rehashing,因?yàn)樗{(diào)用hash方法找到新的bucket位置。
5、“你了解重新調(diào)整HashMap大小存在什么問題嗎?”
當(dāng)重新調(diào)整HashMap大小的時候,確實(shí)存在條件競爭,因?yàn)槿绻麅蓚€線程都發(fā)現(xiàn)HashMap需要重新調(diào)整大小了,它們會同時試著調(diào)整大小。在調(diào)整大小的過程中,存儲在LinkedList中的元素的次序會反過來,因?yàn)橐苿拥叫碌腷ucket位置的時候,HashMap并不會將元素放在LinkedList的尾部,而是放在頭部,這是為了避免尾部遍歷(tail traversing)。如果條件競爭發(fā)生了,那么就死循環(huán)了。這個時候,你可以質(zhì)問面試官,為什么這么奇怪,要在多線程的環(huán)境下使用HashMap呢?