3. 你重寫過hashcode和equals麼,要注意什麼?
阿新 • • 發佈:2019-02-09
SUN官方的文件中規定"如果重定義equals方法,就必須重定義hashCode方法,以便使用者可以將物件插入到雜湊(雜湊)表中"
那麼 SUN 公司是出於什麼考慮做了這個規定呢?
在集合框架中的HashSet
,HashTable
和HashMap
都使用雜湊表的形式儲存資料,而hashCode
計算出來的雜湊碼便是它們的身份證。雜湊碼的存在便可以:
- 快速定位物件,提高雜湊表集合的效能。
- 只有當雜湊表中物件的索引即
hashCode
和物件的屬性即equals
同時相等時,才能夠判斷兩個物件相等。 - 從上面可以看出,雜湊碼主要是為雜湊表服務的,其實如果不需要使用雜湊表,也可以不重寫
hashCode
equals
的同時需要重寫hashCode
,以避免後續開發不必要的麻煩。 - hashCode方法可以這樣理解:它返回的就是根據物件的記憶體地址換算出的一個值。這樣一來,當集合要新增新的元素時,先呼叫這個元素的hashCode方法,就一下子能定位到它應該放置的物理位置上。如果這個位置上沒有元素,它就可以直接儲存在這個位置上,不用再進行任何比較了;如果這個位置上已經有元素了,就呼叫它的equals方法與新元素進行比較,相同的話就不存了,不相同就雜湊其它的地址。這樣一來實際呼叫equals方法的次數就大大降低了,幾乎只需要一兩次。
重寫equals時需要注意滿足java語言規範對於equals的要求:
Java語言規範要求equals
需要具有如下的特性:
- 自反性:對於任何非空引用 x,
x.equals()
應該返回true
。 - 對稱性:對於任何引用 x 和 y,當且僅當
y.equals(x)
返回true
,x.equals(y)
也應該返回true
。 - 傳遞性:對於任何引用 x、y 和 z,如果
x.equals(y)
返回true
,y.equals(z)
也應返回同樣的結果。 - 一致性:如果 x 和 y 引用的物件沒有發生變化,反覆呼叫
x.equals(y)
應該返回同樣的結果。 - 對於任意非空引用 x,
x.equals(null)
false
。
重寫equals時,用eclipes生成的原始碼:
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + age;
result = prime * result + ((name == null) ? 0 : name.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Dog other = (Dog) obj;
if (age != other.age)
return false;
if (name == null) {
if (other.name != null)
return false;
} else if (!name.equals(other.name))
return false;
return true;
}
注意:1.equals
與hashCode
的定義必須一致,兩個物件equals
為true
,就必須有相同的hashCode
。反之,如果兩個物件的hashcode相同,equals不一定相同。2.當重寫equals方法時,一定要同時把hashcode方法一併重寫,因為要保證在實現hash表的擴充套件性