Java理論與實踐:哈希
每個Java對象都有hashCode()和 equals()方法。許多類忽略(Override)這些方法的缺省實施,以在對象實例之間提供更深層次的語義可比性。在Java理念和實踐這一部分,Java開發人員Brian Goetz向您介紹在創建Java類以有效和準確定義hashCode()和equals()時應遵循的規則和指南。您可以在討論論壇與作者和其它讀者一同探討您對本文的看法。(您還可以點擊本文頂部或底部的討論進入論壇。)
雖然Java語言不直接支持關聯數組 -- 可以使用任何對象作為一個索引的數組 -- 但在根Object類中使用hashCode()方法明確表示期望廣泛使用HashMap(及其前輩Hashtable)。理想情況下基于散列的容器提供有效插入和有效檢索;直接在對象模式中支持散列可以促進基于散列的容器的開發和使用。
定義對象的相等性
Object類有兩種方法來推斷對象的標識:equals()和hashCode()。一般來說,如果您忽略了其中一種,您必須同時忽略這兩種,因為兩者之間有必須維持的至關重要的關系。特殊情況是根據equals() 方法,如果兩個對象是相等的,它們必須有相同的hashCode()值(盡管這通常不是真的)。
特定類的equals()的語義在Implementer的左側定義;定義對特定類來說equals()意味著什么是其設計工作的一部分。Object提供的缺省實施簡單引用下面等式:
public boolean equals(Object obj) { return (this == obj); }
在這種缺省實施情況下,只有它們引用真正同一個對象時這兩個引用才是相等的。同樣,Object提供的hashCode()的缺省實施通過將對象的內存地址對映于一個整數值來生成。由于在某些架構上,地址空間大于int值的范圍,兩個不同的對象有相同的hashCode()是可能的。如果您忽略了hashCode(),您仍舊可以使用System.identityHashCode()方法來接入這類缺省值。
忽略 equals() -- 簡單實例
缺省情況下,equals()和hashCode()基于標識的實施是合理的,但對于某些類來說,它們希望放寬等式的定義。例如,Integer類定義equals() 與下面類似:
public boolean equals(Object obj) {
return (obj instanceof Integer
&& intvalue() == ((Integer) obj).intvalue());
}
在這個定義中,只有在包含相同的整數值的情況下這兩個Integer對象是相等的。結合將不可修改的Integer,這使得使用Integer作為HashMap中的關鍵字是切實可行的。這種基于值的Equal方法可以由Java類庫中的所有原始封裝類使用,如Integer、Float、Character和Boolean以及String(如果兩個String對象包含相同順序的字符,那它們是相等的)。由于這些類都是不可修改的并且可以實施hashCode()和equals(),它們都可以做為很好的散列關鍵字。