案例:
比如一個人在不同的時期在系統中生成了兩個實例,要想判斷這兩個實例是不是一個人,比較身份證號就可以了。假定這兩個實例,一個是16歲時建立的檔案,一個是24歲入職建立的檔案,如果不重寫equals方法,這兩個實例肯定不是一個人了。
如果不被重寫(原生)的hashCode和equals是什么樣的?
1 . 不被重寫(原生)的hashCode值是根據內存地址換算出來的一個值。
2 . 不被重寫(原生)的equals方法是嚴格判斷一個對象是否相等的方法(object1 == object2)。
我們先來看一下Object.hashCode的通用約定(摘自《Effective Java》第45頁)
- 在一個應用程序執行期間,如果一個對象的equals方法做比較所用到的信息沒有被修改的話,那么,對該對象調用hashCode方法多次,它必須始終如一地返回 同一個整數。在同一個應用程序的多次執行過程中,這個整數可以不同,即這個應用程序這次執行返回的整數與下一次執行返回的整數可以不一致。
- 如果兩個對象根據equals(Object)方法是相等的,那么調用這兩個對象中任一個對象的hashCode方法必須產生同樣的整數結果。
- 如果兩個對象根據equals(Object)方法是不相等的,那么調用這兩個對象中任一個對象的hashCode方法,不要求必須產生不同的整數結果。然而,程序員應該意識到這樣的事實,對於不相等的對象產生截然不同的整數結果,有可能提高散列表(hash table)的性能。
如果只重寫了equals方法而沒有重寫hashCode方法的話,則會違反約定的第二條:相等的對象必須具有相等的散列碼(hashCode)
同時對於HashSet和HashMap這些基於散列值(hash)實現的類.
object對象中的 public boolean equals(Object obj),對於任何非空引用值 x 和 y,當且僅當 x 和 y 引用同一個對象時,此方法才返回 true;
注意:當此方法被重寫時,通常有必要重寫 hashCode 方法,以維護 hashCode 方法的常規協定,該協定聲明相等對象必須具有相等的哈希碼。如下:
(1)當obj1.equals(obj2)為true時,obj1.hashCode() == obj2.hashCode()必須為true
(2)當obj1.hashCode() == obj2.hashCode()為false時,obj1.equals(obj2)必須為false
如果不重寫equals,那么比較的將是對象的引用是否指向同一塊內存地址,重寫之后目的是為了比較兩個對象的value值是否相等。
這樣如果我們對一個對象重寫了euqals,意思是只要對象的成員變量值都相等那么euqals就等於true,但不重寫hashcode,那么我們再new一個新的對象,
當原對象.equals(新對象)等於true時,兩者的hashcode卻是不一樣的,由此將產生了理解的不一致,如在存儲散列集合時(如Set類),將會存儲了兩個值一樣的對象,
導致混淆,因此,就也需要重寫hashcode()
舉例說明:
package com.zcj.eg002; import java.util.*; public class HelloWorld { public static void main(String[] args) { Name n1 = new Name("zcj001"); Name n2 = new Name("zcj001"); Collection c = new HashSet(); c.add(n1); System.out.println("------------"); c.add(n2); System.out.println("------------"); System.out.println(n1.equals(n2)); System.out.println("------------"); System.out.println(n1.hashCode()); System.out.println(n2.hashCode()); System.out.println(c); } } class Name { private String id; public Name(String id) { this.id = id; } public String toString(){ return this.id; } public boolean equals(Object obj) { if (obj instanceof Name) { Name name = (Name) obj; System.out.println("***equal***"+ name.id); return (id.equals(name.id)); } return super.equals(obj); } public int hashCode() { Name name = (Name) this; System.out.println("***Hash***" + name.id); return id.hashCode(); } }
當重寫equals()和hashCode()運行的結果如下:
equals為true,hashCode的值相同
當只重寫equals()不重寫hashCode()運行結果如下:
equals為true,hashCode的值不同違反約定的第二條
當只重寫hashCode()不重寫equals()運行結果如下: