Map的Key你真的了解嗎?
何類作為Map的Key?為什么HashMap中String、Integer這樣的包裝類適合作為Key?如果使用Object作為HashMap的Key,應(yīng)該怎么辦?” 這個(gè)問題看似簡單,但實(shí)際上涉及到HashMap的核心機(jī)制,面試中說得清楚絕對能讓面試官眼前一亮!
話不多說,讓我們通過一個(gè)小故事,邊學(xué)邊聊。
初識問題:能否使用任何類作為Map的Key?
故事從小明找工作說起。小明在面試時(shí)被問到:“你能用任何類作為Map的Key嗎?”
小明想了想,答:“理論上可以吧,但會有坑?!?/p>
沒錯(cuò),理論上任何類都可以作為Map的Key。但是!能否真正高效和正確地使用,得滿足兩個(gè)條件:
- 必須重寫hashCode()方法:這是因?yàn)镠ashMap基于哈希表實(shí)現(xiàn),hashCode()決定了對象的存儲位置。
- 必須重寫equals()方法:當(dāng)兩個(gè)對象的hashCode相同,HashMap會使用equals()方法來判斷它們是否真的相等。
如果你用的類沒有重寫這兩個(gè)方法,HashMap就可能無法正確判斷Key是否相等,導(dǎo)致奇怪的行為。比如,明明存進(jìn)去了,卻取不出來。
為什么String和Integer適合作為Key?
接著,面試官進(jìn)一步追問:“那為什么String和Integer這樣的包裝類適合作為Key呢?”
小明頓時(shí)慌了,但冷靜下來,他回憶起學(xué)過的知識,侃侃而談。
String
- String的hashCode()實(shí)現(xiàn)簡單明了,基于內(nèi)容計(jì)算哈希值。
- 它的equals()方法也是內(nèi)容比較,完全符合HashMap的需求。
- 不可變性:String是不可變類,哈希值一旦計(jì)算,就不會因內(nèi)容變化而失效。
Integer
- Integer的hashCode()直接返回它的值,簡單高效。
- equals()也是基于值的比較。
- 同樣是不可變的包裝類,Key的狀態(tài)不會因外部修改而改變。
對比之下,如果你使用一個(gè)可變對象作為Key,比如一個(gè)List,情況會變得復(fù)雜。如果在存入HashMap后,你修改了List的內(nèi)容,它的hashCode就會改變,導(dǎo)致HashMap無法正確找到存儲的位置。
如果使用Object作為Key,該怎么辦?
這時(shí),面試官繼續(xù)刁難:“假如我想用自己的類Person作為Key呢?”
小明心里有底了,他微微一笑:“那就得自己實(shí)現(xiàn)hashCode()和equals()方法了。”
如何實(shí)現(xiàn)?
以下是小明舉的例子:
圖片
- hashCode():使用Objects.hash()方法將name和age的值組合成一個(gè)哈希值,保證哈希分布的均勻性。
- equals():確保當(dāng)兩個(gè)對象的name和age都相同時(shí),它們被認(rèn)為是相等的。
避坑指南:Key需要注意哪些問題?
1、不可變性
Key最好是不可變的(如String和Integer),否則會導(dǎo)致數(shù)據(jù)一致性問題。
2、重寫規(guī)則一致
如果你重寫了equals(),就必須重寫hashCode(),并保證規(guī)則一致:
- 如果兩個(gè)對象相等(equals()返回true),它們的hashCode必須相等。
- 如果兩個(gè)對象不相等,它們的hashCode盡量不同。
3、合理選擇Key
如果使用復(fù)雜對象作為Key,確保它的字段值不會頻繁變動,否則建議使用唯一標(biāo)識符(如ID)。
總結(jié)
面試結(jié)束后,小明總結(jié)道:
- 能否使用任何類作為Map的Key?:可以,但必須保證重寫hashCode()和equals()方法。
- 為什么String和Integer適合作為Key?:它們有良好的hashCode()和equals()實(shí)現(xiàn),并且是不可變類。
- 如果使用自定義類作為Key?:重寫hashCode()和equals()方法,確保Key的唯一性和一致性。