1.從HashMap說起
我們知道Map以鍵值對的形式來存儲數據。有一點值得說明的是,如果要使用我們自己的類作爲鍵,我們必須同時重寫hashCode() 和 equals()兩個方法。HashMap使用equals方法來判斷當前的鍵是否與表中的鍵相同。equals()方法需要滿足以下5個條件
- 自反性 x.equals(x) 一定返回true
- 對稱性 x.equals(y)返回true,則y.equals(x) 也返回true
- 傳遞性 x.equals(y)返回true,y.equals(z)返回true,則x.equals(y)返回true
- 一致性 如果對象中的信息沒有改變,x.equals(y)要麼一直返回true,要麼一直返回false
- 對任何不是null的x,想x.equals(null)一定返回false
2.散列
散列的價值在於速度。
假如鍵沒有按照一定的順序進行保存,那麼查詢的時候就只能按照順序進行線性查詢,然而,線性查詢是最慢的查詢方式。所以,將鍵值按照一定的順序排序,並且使用二分查找能購有效的提升速度。散列在此之上,更近一步,他將鍵保存在數組中(數組的查詢速度最快),用數組來表示鍵的信息,但是由於Map的容量是可變的,而數組的容量是不變的。要解決這個問題,數組中存的並不是鍵本身,而是鍵對象生成的一個數字,將其作爲數組的下標,這個數字就是散列碼。
而這種辦法所產生的問題就是下標重複。而我們的解決辦法就是配合equals來確定鍵值。
查詢的過程首先就是計算散列碼,然後用散列碼來查詢函數(下標),通常,我們的數組中保存的是值的list,因此,我們計算出散列碼之後,通過下表取到的對應部分的list,然後通過equals就可以快速找到鍵值。
3.HashCode
hashCode函數是用來生成散列碼的,我們看看Integer的計算方式(ps:我們自己的對象我們要選擇自己的方式)
public static int hashCode(int value) {
return value;
}
這裏不在多說,我們自己的類有自己的散列碼實現就好。
4. 以HashMap的get方法來說明
public V get(Object key) {
if (key == null) {
HashMapEntry<K, V> e = entryForNullKey;
return e == null ? null : e.value;
}
int hash = Collections.secondaryHash(key);
HashMapEntry<K, V>[] tab = table;
for (HashMapEntry<K, V> e = tab[hash & (tab.length - 1)];
e != null; e = e.next) {
K eKey = e.key;
if (eKey == key || (e.hash == hash && key.equals(eKey))) {
return e.value;
}
}
return null;
}
- int hash = Collections.secondaryHash(key); 計算出散列碼
- HashMapEntry
K eKey = e.key;
if (eKey == key || (e.hash == hash && key.equals(eKey))) {
return e.value;
}
- 若地址相同,返回值,
- 若hash值相等且equals返回true,返回值
5.總結
不知道各位朋友看了這篇之後是否理解了散列和散列碼。還是原來就懂,被我這麼一頓bb,不懂了!!!