重寫equals時還必須重寫hashcode方法
equals和hashcode方法是object物件中的方法。
equals與hashcode間的關係是這樣的:
1、如果兩個物件相同(即用equals比較返回true),那麼它們的hashCode值一定要相同;
2、如果兩個物件的hashCode相同,它們並不一定相同(即用equals比較返回false)
我們都知道java中的List集合是有序的,因此是可以重複的,而set集合是無序的,因此是不能重複的,那麼怎麼能保證不能被放入重複的元素呢?
但靠equals方法一樣比較的話,如果原來集合中以後又10000個元素了,那麼放入10001個元素,難道要將前面的所有元素都進行比較,看看是否有重複,歐碼噶的,這個效率可想而知,因此hashcode就應遇而生了.
java就採用了hash表,利用雜湊演算法(也叫雜湊演算法),就是將物件資料根據該物件的特徵使用特定的演算法將其定義到一個地址上,那麼在後面定義進來的資料只要看對應的hashcode地址上是否有值,那麼就用equals比較,如果沒有則直接插入,
只要就大大減少了equals的使用次數,執行效率就大大提高了。
繼續上面的話題,為什麼必須要重寫hashcode方法,
其實簡單的說就是為了保證同一個物件,而不是new出的多個物件,保證在equals相同的情況下hashcode值必定相同.
如果重寫了equals而未重寫hashcode方法,可能就會出現兩個沒有關係的物件equals相同的(因為equal都是根據物件的特徵進行重寫的),但hashcode確實不相同的.
但不重寫hashcode,那麼我們再new一個新的物件,當原物件.equals(新物件)等於true時,兩者的hashcode卻是不一樣的
,由此將產生了理解的不一致,如在儲存雜湊集合時(如Set類),將會儲存了兩個值一樣的物件,導致混淆,
因此,就也需要重寫hashcode()
示例:
/** * Created by chengxiao on 2016/11/15. */ public class MyTest { private static class Person{ int idCard; String name; public Person(int idCard, String name) { this.idCard = idCard; this.name = name; } @Override public boolean equals(Object o) { if (this == o) { return true; } if (o == null || getClass() != o.getClass()){ return false; } Person person = (Person) o; //兩個物件是否等值,通過idCard來確定 return this.idCard == person.idCard; } } public static void main(String []args){ HashMap<Person,String> map = new HashMap<Person, String>(); Person person = new Person(1234,"喬峰"); //put到hashmap中去 map.put(person,"天龍八部"); //get取出,從邏輯上講應該能輸出“天龍八部” System.out.println("結果:"+map.get(new Person(1234,"蕭峰"))); } }
實際輸出結果:
null
如果我們已經對HashMap的原理有了一定了解,這個結果就不難理解了。儘管我們在進行get和put操作的時候,使用的key從邏輯上講是等值的(通過equals比較是相等的),但由於沒有重寫hashCode方法,所以put操作時,key(hashcode1)-->hash-->indexFor-->最終索引位置 ,而通過key取出value的時候 key(hashcode1)-->hash-->indexFor-->最終索引位置,由於hashcode1不等於hashcode2,導致沒有定位到一個數組位置而返回邏輯上錯誤的值null(也有可能碰巧定位到一個數組位置,但是也會判斷其entry的hash值是否相等,上面get方法中有提到。)
所以,在重寫equals的方法的時候,必須注意重寫hashCode方法,同時還要保證通過equals判斷相等的兩個物件,呼叫hashCode方法要返回同樣的整數值。而如果equals判斷不相等的兩個物件,其hashCode可以相同(只不過會發生雜湊衝突,應儘量避免)。