HashMap, equals, hashCode
equals和hashCode是Object類中的兩個方法。
這兩個方法會被所有的類繼承,也就是說所有的類都有這兩個方法。
這兩個方法可以被重寫。
重寫equals和hashCode有一個原則:
如果兩個對象是equals的,那麽盡量使hashCode相同;
如果兩個對象的hashCode相同,那麽這兩個對象不一定equals。
最近有一個人問我一個問題。
給一個Person類追加了一個equals方法,但是沒有重寫hashCode方法有沒有什麽問題?
當然沒有問題了,但是他說是有問題的。問題出在了HashMap這裏。如果把這個Person對象作為key放到HashMap中,value暫且不管,會出問題。
以上是環境。盡管他說的不太對,但是有一定的啟發。
HashMap存在的意義是能夠方便的獲取某一個key所對應的value。而通過這個key去獲取對象的時候會調用這個key的hashCode方法。
public class HashEqualsTester { public static void main(String[] args) { Person p1 = new Person(); p1.setId("abc"); p1.setName("ABC"); p1.setAge(25); p1.setDescription("I am just person 1."); Person p2 = new Person(); p2.setId("abc"); p2.setName("ABC"); p2.setAge(25); p2.setDescription("I am just person 2."); Map<Person, String> map = new HashMap<Person, String>(); map.put(p1, p1.getDescription()); map.put(p2, p2.getDescription()); } } class Person { private String id; private String name; private Integer age; private String description; @Override public int hashCode() { System.out.println("hashCode called..."); return 1; } // get and set }
執行main函數,會打印:
hashCode called...
hashCode called...
但是我們打印map的時候,如:
System.out.println(map);
執行結果為:
hashCode called...
{[email protected]1=I am just person 2.}
並且,map中只存在一條記錄。也就是說當兩個對象的hashCode值相同的時候,只保存一個值。
如果hashCode不相同呢?
如果兩個對象的hashCode相同,會繼續調用對象的equals方法,如果兩個對象是equals的,那麽也只會在map中存一個值,並且是後一個值。
把代碼放一下:
package hash.equals; import java.util.HashMap; import java.util.Map; public class HashEqualsTester { public static void main(String[] args) { Person p1 = new Person(); p1.setId("abc"); p1.setName("ABC"); p1.setAge(25); p1.setDescription("I am just person 1."); Person p2 = new Person(); p2.setId("abc"); p2.setName("ABC"); p2.setAge(25); p2.setDescription("I am just person 2."); Map<Person, String> map = new HashMap<Person, String>(); map.put(p1, p1.getDescription()); map.put(p2, p2.getDescription()); System.out.println(map); System.out.println(map.get(p1)); System.out.println(map.get(p2)); } } class Person { private String id; private String name; private Integer age; private String description; @Override public boolean equals(Object person) { System.out.println("equals called..."); return true; } @Override public int hashCode() { System.out.println("hashCode called..."); return 1; } public String getId() { return id; } public void setId(String id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public Integer getAge() { return age; } public void setAge(Integer age) { this.age = age; } public String getDescription() { return description; } public void setDescription(String description) { this.description = description; } }
執行結果:
hashCode called... hashCode called... equals called... hashCode called... {[email protected]1=I am just person 2.} hashCode called... I am just person 2. hashCode called... equals called... I am just person 2.
話雖如此,這裏面仍然有幾個東西不太明確。
1,為什麽要用一個對象作為map的key呢?
2,知道了這些有什麽意義呢?
3,有一本java書籍上說過,除非你有很正當的理由,不然別去重寫你的equals和hashCode方法。
=================================
* Note that it is generally necessary to override the {@code hashCode}
* method whenever this method is overridden, so as to maintain the
* general contract for the {@code hashCode} method, which states
* that equal objects must have equal hash codes.
這是java官方的equals中的一段描述,如果對equals方法進行了override的話,重寫hashCode通常就是必須的了。
HashMap, equals, hashCode