在每個覆蓋了equals 方法的類中,也必須覆蓋 hashCode 方法.
否則違反Object.hashCode 通用規定,從而導致無法結合所有基于散列的集合一起正常運作.
Object.hashCode 約定的內容:
- 在應用程序執行期間,只要對象的equals方法的比較操作所用到的信息沒有被修改,那么多次調用hashCode方法都必須始終如一的返回同一個整數. 同一個程序被多次執行過程中, hashCode返回的整數可以不一致.
- 如果 x.equals(y) == true 那么要求 x.hashCode() == y.hashCode()
- 如果 x.equals(y) == false, 沒有要求 x.hashCode != y.hashCode, 但是不同對象產生不同的hashCode有利于hash tables 的性能.
一個好的散列函數通常傾向于:為不相等的對象產生不相等的散列碼.
簡單的hash方法:
- int result = 17 (要求非0的整數即可)
- 對于對象中的每個關鍵域f(也就是 equals 中涉及的每個域),
- 2.1 計算該域的散列碼 c:
- i. boolean 類型: c = (f ? 1:0)
- ii. byte,char,shot,int類型, c = int(f)
- iii. longs類型: c = (int)(f ^ (f >> 32))
- iv. float類型: c = Float.floatToIntBits(f)
- v. double類型: fb = Double.doubleToLongBits(f), c = (int)(fb ^ ( fb >> 32))
- vi. 對象引用類型: c = (f = null ? 0: f.hashCode())
- vii. 數組類型: c = Arrays.hashCode()- 2.2 rerult = 31 * result + c (使用奇素數31,防止乘法溢出, 并且 31 * i = (i << 5) - i)
- 2.1 計算該域的散列碼 c:
- 對于對象中的每個關鍵域f(也就是 equals 中涉及的每個域),
- return result
- 檢查是否滿足相等的實例具有相等的散列碼.
緩存hashCode,并延遲初始化:
private volatile int hashCode;
// equals 方法比較涉及的三個域: short areaCode, short prefix, short lineNumber
@Override
public int hashCode() {
int result = hashCode;
if (result == null) {
result = 17;
result = 31 * result * areaCode;
result = 31 * result * prefix;
result = 31 * result * lineNumber;
hashCode = result;
}
return result;
}
**不要試圖從散列碼計算中排除一個對象的關鍵部分來提高性能.這樣雖然計算hashCode可能會快一點,但是hash表不一定好.