看似簡單的hashCode和equals面試題,竟然有這麼多坑!

Java菜分享發表於2019-03-05

hashCode()方法和equals()區別與聯絡這到面試題,看似簡單,根據以往面試星友的情況來說,絕大部分人都不能很好的回答出來,要麼沒有邏輯,想到一句就說一句,要麼抓不住重點,答非所問。從這個很小的面試題上我們就可以看出來,對於任何一個面試題來說,都是要清晰有條理的回答。那麼如何才能回答到點子上並且讓面試官覺得你的邏輯清晰哪?

首先,我們要介紹hashCode()和equals()方法的作用是是什麼,然後才說他的區別,說了區別之後再說使用的時候需要注意到的地方,這樣的回答思路基本是OK的,如果你在瞭解一些其他人不知道的那就更好了!下邊我們就開始介紹:

一、hashCode()和equals()是什麼?

hashCode()方法和equals()方法的作用其實一樣,在Java裡都是用來對比兩個物件是否相等一致。

二、hashCode()和equals()的區別

下邊從兩個角度介紹了他們的區別:一個是效能,一個是可靠性。他們之間的主要區別也基本體現在這裡。

1、equals()既然已經能實現對比的功能了,為什麼還要hashCode()呢?

因為重寫的equals()裡一般比較的比較全面比較複雜,這樣效率就比較低,而利用hashCode()進行對比,則只要生成一個hash值進行比較就可以了,效率很高。

2、hashCode()既然效率這麼高為什麼還要equals()呢?

因為hashCode()並不是完全可靠,有時候不同的物件他們生成的hashcode也會一樣(生成hash值得公式可能存在的問題),所以hashCode()只能說是大部分時候可靠,並不是絕對可靠,所以我們可以得出(PS:以下兩條結論是重點,很多人面試的時候都說不出來):

  • equals()相等的兩個物件他們的hashCode()肯定相等,也就是用equals()對比是絕對可靠的。

  • hashCode()相等的兩個物件他們的equals()不一定相等,也就是hashCode()不是絕對可靠的。

三、hashCode()和equals()使用的注意事項

1、對於需要大量並且快速的對比的話如果都用equals()去做顯然效率太低,所以解決方式是,每當需要對比的時候,首先用hashCode()去對比,如果hashCode()不一樣,則表示這兩個物件肯定不相等(也就是不必再用equals()去再對比了),如果hashCode()相同,此時再對比他們的equals(),如果equals()也相同,則表示這兩個物件是真的相同了,這樣既能大大提高了效率也保證了對比的絕對正確性!

看似簡單的hashCode和equals面試題,竟然有這麼多坑!

2、這種大量的並且快速的物件對比一般使用的hash容器中,比如HashSet,HashMap,HashTable等等,比如HashSet裡要求物件不能重複,則他內部必然要對新增進去的每個物件進行對比,而他的對比規則就是像上面說的那樣,先hashCode(),如果hashCode()相同,再用equals()驗證,如果hashCode()都不同,則肯定不同,這樣對比的效率就很高了。

3、然而hashCode()和equals()一樣都是基本類Object裡的方法,而和equals()一樣,Object裡hashCode()裡面只是返回當前物件的地址,如果是這樣的話,那麼我們相同的一個類,new兩個物件,由於他們在記憶體裡的地址不同,則他們的hashCode()不同,所以這顯然不是我們想要的,所以我們必須重寫我們類的hashCode()方法,即一個類,在hashCode()裡面返回唯一的一個hash值,比如下面:

看似簡單的hashCode和equals面試題,竟然有這麼多坑!

由於標識這個類的是他的內部的變數num和name,所以我們就根據他們返回一個hash值,作為這個類的唯一hash值。

所以如果我們的物件要想放進hashSet,並且發揮hashSet的特性(即不包含一樣的物件),則我們就要重寫我們類的hashCode()和equals()方法了。像String,Integer等這種類內部都已經重寫了這兩個方法。

當然如果我們只是平時想對比兩個物件 是否一致,則只重寫一個equals(),然後利用equals()去對比也行的。

四、擴充套件

1、阿里巴巴開發規範明確規定:

看似簡單的hashCode和equals面試題,竟然有這麼多坑!

  • 只要重寫 equals,就必須重寫 hashCode;

  • 因為 Set 儲存的是不重複的物件,依據 hashCode 和 equals 進行判斷,所以 Set 儲存的物件必須重寫這兩個方法;

  • 如果自定義物件做為 Map 的鍵,那麼必須重寫 hashCode 和 equals;

  • String 重寫了 hashCode 和 equals 方法,所以我們可以非常愉快地使用 String 物件作為 key 來使用;

2、什麼時候需要重寫?

一般的地方不需要過載hashCode,只有當類需要放在HashTable、HashMap、HashSet等等hash結構的集合時才會過載hashCode。

3、那麼為什麼要過載hashCode呢?

如果你重寫了equals,比如說是基於物件的內容實現的,而保留hashCode的實現不變,那麼很可能某兩個物件明明是“相等”,而hashCode卻不一樣。

這樣,當你用其中的一個作為鍵儲存到hashMap、hasoTable或hashSet中,再以“相等的”找另一個作為鍵值去查詢他們的時候,則根本找不到。

4、為什麼equals()相等,hashCode就一定要相等,而hashCode相等,卻不要求equals相等?

  • 因為是按照hashCode來訪問小記憶體塊,所以hashCode必須相等。

  • HashMap獲取一個物件是比較key的hashCode相等和equals為true。

之所以hashCode相等,卻可以equal不等,就比如ObjectA和ObjectB他們都有屬性name,那麼hashCode都以name計算,所以hashCode一樣,但是兩個物件屬於不同型別,所以equals為false。

5、為什麼需要hashCode?

  • 通過hashCode可以很快的查到小記憶體塊。

  • 通過hashCode比較比equals方法快,當get時先比較hashCode,如果hashCode不同,直接返回false。

五、總結

從上邊一道簡單的面試題我們可以擴充套件到其他面試題的回答上,首先你要對這個東西明白,然後才能有條理,清晰的給面試官介紹你掌握的內容,描述的過程也是很重要的,不能毫無章法,要遊刃有餘。這一點相信是很多面試者最吃虧的地方,自己明白的東西都講不清楚,沒有條理!

面試的時候,我們的理想境界大概就是“會的東西你能夠講明白,讓面試官覺得你對這個東西很有研究;不會的東西你能夠說出來,讓面試官覺得你對這個東西有了解”!為了這個目標,2019年春節過後,我已經給自己立了一個flag,每天有條理、清晰的整理一道面試題,分享到自己的知識星球裡邊,和大家一起學習交流,幫助大家養成良好的面試問題回答習慣,希望能夠靠自己的一點經驗給大家帶來力所能及的幫助。以上關於hashCode和equals常見的面試題和回答思路也是其中已經整理出來的一道題目。

歡迎工作一到五年的Java工程師朋友們加入Java程式設計師開發: 854393687

 群內提供免費的Java架構學習資料(裡面有高可用、高併發、高效能及分散式、Jvm效能調優、Spring原始碼,MyBatis,Netty,Redis,Kafka,Mysql,Zookeeper,Tomcat,Docker,Dubbo,Nginx等多個知識點的架構資料)合理利用自己每一分每一秒的時間來學習提升自己,不要再用"沒有時間“來掩飾自己思想上的懶惰!趁年輕,使勁拼,給未來的自己一個交代! 


相關文章