在物件導向 - Java那些事兒 一文中,我們後續留了一個話題,引入了Set,我們知道Set裡面的元素是不可以重複的,話不多說,上程式碼:
精簡了上一章中的Person類,保留了isSame()方法;
想必大家看到類似的程式碼開始懷疑筆者是不是又挖坑讓大夥跳了吧,來看一下結果。
沒錯,有坑,同樣是物件,都是放到了set中,一個列印size()是1,另一個列印size()是2。在物件導向 - Java那些事兒 一文中,我們在Person這個類,雖然寫了一個isSame()方法來判斷業務上是否相等,看上去是解決了當時的問題,然而不知不覺的為自己挖了坑。假設我們現在正在給使用者批量發工資,張三出現了兩次,雖然我們用Set去了重,但還是會給張三發兩次工資。
在Java程式中,有很多的“公約”,我們稱之為程式設計規範,遵守這些規範實現你的程式碼,會讓你避開很多坑。要判斷兩個物件的內容是否相等,不要自己寫方法(isSame())去判斷,而是應該重寫父類的 equals方法(這裡的父類是Object),在說說Java裡的equals(上) - Java那些事兒,我們說過String重寫了equals()方法,所以這兒列印size結果是1,而Person沒有重寫,因此Set沒法判斷這兩個"張三"是否是同一個人,列印size結果是2。
我們再看以下程式碼:
結果當然是全是false(這個應該沒人能答錯了吧),看結果
下面我們像String一樣,重寫一下Person的equals方法。
看起來沒問題,別忘 了,如果是重寫方法,我們在方法上要加上@Override註解,加上該註解,編譯器會幫你檢查是否真的覆蓋了父類的方法。編譯一下,居然報錯了。
原來我們跟本就不是重寫(覆蓋)了父類的equals方法,而是自己又寫了一個引數為Person的equals方法,根本不是重寫,只是過載了父類的方法而已。
過載:就是在同一個類中,方法的名字相同,但引數個數、引數的型別不同。
重寫:它是指子類和父類的關係,子類重寫了父類的方法,但方法名、引數型別、引數個數必須相同
下面我們正確的覆蓋一下。
我們寫一段測程式碼測試一下,這裡我們引入了List。
執行一下,perList裡面我們只新增person1,並沒有新增person2,但執行perList.contains(person2)列印的結果居然是true(List裡面包含了person2),只因為重寫了equals()方法,注意:pSet.contains(person2))依舊是false。
再執行本文開始那段程式碼,不出所料,問題依舊
很明顯,Person這個類在重寫equals()方法後,雖然已經支援List,但還不支援Set。要完美支援HashMap,HashSet,LinkedHashMap,ConcurrentHashMap等這些類,不但要重寫equals方法,還需要重寫hashCode()方法。
現在我們在Person類裡重寫一下hashCode()方法
再執行一下,終於看到想要的結果了。
再執行一下本開始那段程式碼,已經是我們想要的結果了。
注:本文中提到的HashMap,HashSet,LinkedHashMap,ConcurrentHashMap,List,hashCode等後續專欄會講解。
總結:當我們在實際業務中需要重寫(覆蓋)equals方法時,根據規範,我們一定要重寫(覆蓋)hashCode方法。在實際開發過程中,不建議一上來就重寫equals方法,除非你有特殊的需求。
回答評論區的問題
在文中一開始的示例中,person1,person2並不是同一個物件,預設equals方法是繼承自Object的,也就相當於==,如果沒有額外的需求明確name相同就視為同一個物件處理,就沒有必要去重寫equals方法了。
注:本專欄文章首發於公眾號:saysayJava。所有示例程式碼均已上傳至公眾號,需要請關注下載。
如果喜歡本系列文章,請為我點贊或順手分享,您的支援是我繼續下去的動力,您也可以在評論區留言想了解的內容,有機會本專欄會做講解,最後別忘了關注一下我。
轉載無限歡迎,但請註明「作者」和「原文地址」。轉載請在文中保留此段,感謝您對作者版權的尊重。如需商業轉載或刊登,請聯絡作者獲得授權。
上一篇:物件導向 - Java那些事兒