1. 程式人生 > >Java程式設計思想——第17章 容器深入研究 讀書筆記(四)

Java程式設計思想——第17章 容器深入研究 讀書筆記(四)

九、雜湊與雜湊碼

HashMap使用equals()判斷當前的鍵是否與表中存在的鍵相同。

正確的equals()方法需滿足一下條件:

1)自反性。x.equals(x) 是true;

2)對稱性。x.equalse(y) 返回true y.equals(x)也得是true;

3)傳遞性。x.equals(y) 返回true ,y.equals(z) 返回true , x.equals(z)返回true;

4)一致性。如果物件中用於等價比較的資訊沒有變,那麼無論多少次 x.equals(y)返回值不會變

5)x.equals(null) 返回 false ;注意:(null).equals(x)報空指標。

強調:預設的Object.equals()只比較物件的地址,因此如果使用自己的類作為HashMap的Key,必須同時過載hashCode()和equals()。

hashCode()並不需要總是能夠返回唯一的標識碼,但是equals()方法必須嚴格的判斷兩個物件是否相等,作為鍵必須唯一否則系統報錯。

    @Override
    public boolean equals(Object o) {
        return o instanceof T && (i.equals(((T) o).i)));
    }

instanceof檢查了此物件是否為null ,是null則返回false。

為速度而雜湊

以線性查詢的是最慢的查詢方式,儲存一組元素最快的資料結構是陣列,所以使用它來標識鍵的資訊(注意,這裡說的是鍵資訊不是鍵本身)。

由於陣列不能調整容量,所以陣列不儲存鍵本身,而是通過鍵物件生成一個雜湊碼,將其作為陣列的下標,這個雜湊碼就是由Object中的、或自己的類覆蓋的hashCode()生成的。

陣列固定的問題解決了,但是鍵可以產生相同的下標,也就是說可能會有衝突。陣列多大不重要,任何鍵總能在陣列中找到它的位置。

於是,查詢一個值的過程首先就是計算雜湊碼,然後使用雜湊碼查詢陣列。如果能夠保證沒有衝突(如果被查詢的值的數量是固定的,就有可能)。

通常,衝突由外部連結處理;陣列並不直接儲存值,而是儲存值的list。然後對list中的值使用equals()方法進行線性查詢。

這部分查詢會比較慢,但是如果雜湊函式好的話,陣列每個位置就有較少的值。

因此,不是查詢整個List而是快速的跳轉到陣列的某個位置,只對很少的元素進行比較。這就是HashMap會如此快的原因。 

我們把散列表的陣列稱為bucket(桶),為了散佈均勻且速度快,桶的容積通常使用質數或者2的整數次方,用LinkedList填充桶。

put()操作,計算key的hashCode(),找到桶中的位置,看LinkedList內容,有值用equals()與值的key相比,相等就替換,不等或者沒有值就在尾部加上新值。

覆蓋hashCode()

桶下標值是無法控制的,這個值依賴於具體的HashMap物件的容量,而容量的改變與容器的充滿程度和負載因子有關。hashCode()生成的結果,經過畜欄裡後成為桶位的下標。

Joshua Blochw指出為寫出一份像樣的hashCode給出了知道:

1)給 int 變數 result 賦予某個非0常量,

2)為物件內每個有意義的域f(既每個可以做equals()操作的域)計算一個int 雜湊碼 c:

域型別:                                                                 計算:

boolean                                                                   c=(f?0:1)

byte、char、short、int                                           c=(int)f

float                                                                         c=(int)(f^(f>>>32))

double                                                                     long I =Double.doubleToLongBits(f); c=(int)(I^(I>>>32))

Object,其equals()呼叫這個域的equals()       c=f.hashCode()

陣列                     對每個元素應用上述規則   

3)合併計算得到雜湊碼

result = 37*result+c                         

 

&nb