當一個類有可能會和其他類發生比較的時候,我們會重寫equals方法,但大多數情況下,都忽略了重寫hashCode方法。
這里說一下重寫hashCode的必要性。
當我們使用HashSet或者HashMap的時候,在比對value|key是否存在時,會調用hashCode方法。
注意,hashSet的contains方法其實是依賴於HashMap的containsKey方法的。
我們來看下containsKey方法的實現:
public boolean containsKey(java.lang.Object paramObject) { return (getEntry(paramObject) != null); } final Entry<K, V> getEntry(java.lang.Object paramObject) { int i = (paramObject == null) ? 0 : hash(paramObject.hashCode()); Entry localEntry = this.table[indexFor(i, this.table.length)]; for (; localEntry != null; localEntry = localEntry.next) { if (localEntry.hash == i) { java.lang.Object localObject; if (((localObject = localEntry.key) == paramObject) || ((paramObject != null) && (paramObject.equals(localObject)))) { return localEntry; } } } return null; }
由上面代碼即可知,hashCode是重要的判斷依據,沒有重寫hashCode,equals表現相等的兩個類,它們的hashCode並不相等。
所以會導致containsKey方法返回false,測試代碼如下:
包含HashCode的類:
package hashset.and.hashcode; public class ClassWithHashCode { public int i; public boolean equals(Object o) { if (o == this) return true; if (o instanceof ClassWithHashCode) { ClassWithHashCode code = (ClassWithHashCode) o; return code.i == i; } return false; } public int hashCode() { return i * 17 + 37; } }
沒有重寫hasCode的類:
package hashset.and.hashcode; public class ClassWithoutHashCode { public int i; public boolean equals(Object o) { if (o == this) return true; if (o instanceof ClassWithoutHashCode) { ClassWithoutHashCode code = (ClassWithoutHashCode) o; return code.i == i; } return false; } }
測試類:
package hashset.and.hashcode; import java.util.HashSet; public class Test { /** * @param args */ public static void main(String[] args) { ClassWithHashCode c1 = new ClassWithHashCode(); ClassWithHashCode c2 = new ClassWithHashCode(); c1.i = 0; c2.i = 0; HashSet<ClassWithHashCode> set = new HashSet<ClassWithHashCode>(); set.add(c1); System.out.println(set.contains(c2)); ClassWithoutHashCode co1 = new ClassWithoutHashCode(); ClassWithoutHashCode co2 = new ClassWithoutHashCode(); co1.i = 0; co2.i = 0; HashSet<ClassWithoutHashCode> set1 = new HashSet<ClassWithoutHashCode>(); set1.add(co1); System.out.println(set.contains(co2)); } }
執行的結果為:
true
false
符合預期。證畢。