書名: Java開發之道作者名: 張振坤 李鐘尉 陳丹丹等編著本章字數: 1681字更新時間: 2018-12-27 19:53:57
陷阱21 一字之差——重寫對象的hashCode方法,但重寫equals方法時參數不是Object類型
在進行程序開發時重寫了equals方法,但是沒有重寫hashCode方法,會導致程序在某些情況下出錯,同樣,如果重寫了對象的hashCode方法,但是沒有重寫equals方法或重寫equals方法時參數不是Object類型,程序在某些情況下也一樣會出現錯誤。
注意
Object類的equals方法其參數必須是Object類型的,如果其直接子類或間接子類重寫該方法,一定要保證其參數也是Object類型,否則在進行一些特殊處理(如判斷HashMap集合中是否包含某個對象)時,程序就會出現錯誤,再有就是在比較兩個對象時,也一定要重寫equals方法,否則程序一樣會出錯。
下面看一個重寫對象的hashCode方法,但是沒有重寫equals方法,導致程序出錯的實例。
例3.21.1 創建類,在該類中重寫對象的hashCode方法,但不重寫equals方法,然后創建該類的兩個實例,將其中一個實例放到HashSet集合中,并判斷該集合中是否包含另一個對象,最后再通過對象的equals 方法比較兩個對象是否相同。(光盤位置:光盤\MR\Instance\3\21\ RewriteHashCodeApp)
import java. util. HashSet; import java. util. Set; public class Book { private String bookType; // 圖書類型 private String bookName; // 圖書名稱 public Book (String bookType, String bookName) { this. bookType = bookType; // 初始化圖書類型 this. bookName = bookName; // 初始化圖書名稱 } // 重寫hashCode方法 public int hashCode () { final int prime = 31; // 用于計算散列碼的基數 int result = 1; // 存放散列碼值的變量 // 通過圖書類型和圖書名稱計算散列碼的值 result = prime * result + ((bookName == null) ? 0 : bookName. hashCode ()); result = prime * result + ((bookType == null) ? 0 : bookType. hashCode ()); return result; // 返回散列碼的值 } public static void main (String[] args) { Book book1 = new Book ("IT", "Java"); // 創建Book的實例book1 Book book2 = new Book ("IT", "Java"); // 創建Book的實例book2 // 輸出兩個對象的散列碼 System.out. println ("對象book1的散列碼是:" + book1. hashCode ()); System.out. println ("對象book2的散列碼是:" + book2. hashCode ()); // 使用HashSet類創建Set集合對象 Set<Book> set = new HashSet<Book>(); set. add (book1); // 將Book的實例book1添加到集合 // 查看集合中是否包含Book的實例book2 boolean bool = set. contains (book2); System.out. println ("Set集合中是否包含對象book2? " + bool); System.out. println ("比較對象book1與book2是否相同?"+ book1. equals (book2)); } }
運行本實例,將在控制臺輸出如圖3.21所示的信息。

圖3.21 重寫hashCode方法而沒重寫equals方法
說明
從圖3.21的輸出結果可以看出,由于重寫了對象的hashCode方法,所以前兩行輸出對象book1和book2的散列碼相同,都是71349994,第3行輸出false,表示Set集合中不包含對象book2,這是由于在重寫hashCode方法的同時,沒有重寫equals方法,所以導致這樣的結果,最后一行也輸出了false,說明兩個對象book1與book2是不相同的,這也是由于在重寫hashCode方法的同時沒有重寫equals方法所導致的。
下面再看一個重寫對象的hashCode方法,同時也重寫了equals方法,但是重寫equals方法的參數不是Object類型導致程序出錯的實例。
例3.21.2 創建類,在該類中重寫對象的hashCode方法,同時也重寫了equals方法,但是重寫equals方法的參數不是Object類型而是Book類型,然后創建該類的兩個實例,將其中一個實例放到HashSet集合中,并判斷該集合中是否包含另一個對象,最后再通過這個equals 方 法 比 較 兩 個 對 象 是 否 相 同。(光 盤 位 置:光 盤 \MR\Instance\3\21\EqualsParameterErrorApp)

運行本實例,將在控制臺輸出如圖3.22所示的信息。

圖3.22 重寫equals方法,但參數不是Object類型
說明
從圖3.22的輸出結果可以看出,由于重寫了對象的hashCode方法,所以前兩行輸出對象book1和book2的散列碼相同,都是71349994,第3行輸出false,表示Set集合中不包含對象book2,這是由于在重寫equals方法時,其參數不是Object類型,實際上該方法在這里是重載了對象的equals方法,而不是重寫對象的equals方法,所以導致這樣的錯誤結果,最后一行輸出了true,說明兩個對象book1與book2是相同的,這是由于該類重載的equals方法,其參數是Book類型,因此可以對Book類的實例進行比較。
下面再看一個重寫對象的hashCode方法,同時也正確地重寫了對象的equals方法,使用程序能夠輸出正確結果的實例。
例3.21.3 創建類,在該類中重寫了對象的hashCode方法和equals方法,然后創建該類的兩個實例,將其中一個實例放到HashSet集合中,并判斷該集合中是否包含另一個對象,最后再通過equals 方法比較兩個對象是否相同。(光盤位置:光盤\MR\Instance\3\21\RightEqualsMethodApp)

運行本實例,將在控制臺輸出如圖3.23所示的信息。

圖3.23 正確重寫對象的方法輸出的結果
說明
本實例之所以輸出了正確的結果,是由于程序正確地重寫了對象的hashCode 方法和equals方法,所以輸出結果的最后兩行都輸出了true,這樣達到了程序預期的要求。
編程準則:一定要同時重寫對象的equals和hashCode方法
無論在什么情況下,如果需要重寫對象的equals方法和hashCode方法,一定要同時重寫這兩個方法,不能只重寫其中的一個方法,并且在重寫對象的equals方法時,一定要注意該方法的形參類型必須要是Object類型的,而不能是其他類型。
- Java Web開發學習手冊
- GitLab Cookbook
- Building Modern Web Applications Using Angular
- Java入門經典(第6版)
- Reactive Programming with Swift
- Mastering Spring MVC 4
- Internet of Things with the Arduino Yún
- Kali Linux Wireless Penetration Testing Beginner's Guide(Third Edition)
- Python機器學習基礎教程
- Visual Basic程序設計實踐教程
- Windows Embedded CE 6.0程序設計實戰
- Python3.5從零開始學
- R用戶Python學習指南:數據科學方法
- UML2面向對象分析與設計(第2版)
- Java EE 7 with GlassFish 4 Application Server