1. hashcode與equals
1.1 hashcode介紹
hashcode()的作用是獲取哈希碼,也稱為散列碼;它實際上是回傳一個int整數,這個哈希碼的作用是確定該物件在哈希表中的索引位置,hashcode()定義在JDK的Object.java中,Java中的任何類都包含有hashcode()函式,散列碼存盤的是鍵值對,它的特點是:能根據鍵快速的檢索出對應的值,這其中就利用到了散列碼,(可以快速找到所需要的物件)
1.2 為什么要有hashcode
以hashset如何檢查重復為例子來說明為什么要有hashcode:
物件加入hashset時,hashset會先計算物件的hashcode值來判斷物件加入的位置,看該位置是否有值,如果沒有,hashset會假設物件沒有重復出現,但如果發現有值,這時會呼叫equals()方法來檢查兩個物件是否真的相同,如果兩者相同,hashset就不會讓其加入操作成功,如果不同,就會重新散列到其他位置,這樣就大大減少了equals的次數,相應的大大提高了執行速度,
如果兩個物件相等,則hashcode一定也是相同的,
兩個物件相等,對兩個物件分別呼叫equals方法都回傳true,
兩個物件有相同的hashcode,它們也不一定相等的,
因此,equals方法被覆寫過,則hashcode方法也必須被覆寫
hashcode()默認行為是對堆上的物件產生獨特值,如果沒有重寫hashcode(),則該class的兩個物件無論如何都不會相等(即使這兩個物件指向相同的資料),
1.3 深入理解 hashCode() 和 equals() 之間的關系
1.3.1 equals() 會有力不從心的時候
上面提到 Set 和 Map 不存放重復的元素(key),這些容器在存盤元素的時必須對元素做出判斷:在當前的容器中有沒有和新元素相同的元素?
你可能會想:這容易呀,直接呼叫元素物件的 equals() 方法進行比較不就行了嗎?
如果容器中的存盤的物件數量較少,這確實是個好主意,但是如果容器中存放的物件達到了一定的規模,要呼叫容器中所有物件的 equals() 方法和新元素進行比較,就不是一件容易的事情了,
就算 equals() 方法的比較邏輯簡單無比,總的來說也是一個時間復雜度為 O(n) 的操作啊,
1.3.2 hashCode() 小力出奇跡
但在散串列的基礎上,判斷“新物件是否和已存在物件相同”就容易得多了,
由于每個物件都自帶有 hashCode(),這個 hashCode 將會用作散串列哈希函式的輸入,hashCode 經過哈希函式計算后得到哈希值,新物件會根據哈希值,存盤到相應的記憶體的單元,
我們不妨假設兩個相同的物件,hashCode() 一定相同,這么一來就體現出哈希函式的威力了,
由于相同的輸入一定會產生相同的輸出,于是如果新物件,和容器中已存在的物件相同,新物件計算出的哈希值就會和已存在的物件的哈希值產生沖突,
這時容器就能判斷:這個新加入的元素已經存在,需要另作處理:覆寫掉原來的元素(key)或舍棄,
按照這個思路,如果這個元素計算出的哈希值所對應的記憶體單元沒有產生沖突,也就是沒有重復的元素,那么它就可以直接插入,
所以當運用 hashCode() 時,判斷是否有相同元素的代價,只是一次哈希計算,時間復雜度為O(1),這極大地提高了資料的存盤性能,
1.3.3 Java 設計 equals(),hashCode() 時約定的規則
前面我們還提到:當輸入樣本量足夠大時,不相同的輸入是會產生相同輸出的,也就是形成哈希沖突,
這么一來就麻煩了,原來我們設定的“如果產生沖突,就意味著兩個物件相同”的規則瞬間被打破,因為產生沖突的很有可能是兩個不同的物件!
而令人欣慰的是我們除了 hashCode() 方法,還有一張王牌:equals() 方法,
也就是說當兩個不相同的物件產生哈希沖突后,我們可以用 equals() 方法進一步判斷兩個物件是否相同,
這時 equals() 方法就相當重要了,這個情況下它必須要能判定這兩個物件是不相同的,
- 講到這里就引出了 Java 程式設計中一個重要原則:
如果兩個物件是相等的,它們的 equals() 方法應該要回傳 true,它們的 hashCode() 需要回傳相同的結果,
但有時候面試不會問得這么直接,他會問你:兩個物件的 hashCdoe() 相同,它的 equals() 方法一定要回傳 true,對嗎?
那答案肯定不對,因為我們不能保證每個程式設計者,都會遵循編碼約定,
有可能兩個不同物件的hashCode()會回傳相同的結果,但是由于他們是不同的物件,他們的 equals() 方法會回傳false,
如果你理解上面的內容,這個問題就很好解答,我們再回顧一下:
如果兩個物件的 hashCode() 相同,將來就會在散串列中產生哈希沖突,但是它們不一定是相同的物件呀,
當產生哈希沖突時,我們還得通過 equals() 方法進一步判斷兩個物件是否相同,equals() 方法不一定會回傳 true,
這也是為什么 Java 官方推薦我們在一個類中,最好同時重寫 hashCode() 和 equals() 方法的原因,
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/288194.html
標籤:其他
上一篇:Spring Native 0.10.0 發布,重大突破!!
下一篇:PHP中PDO關閉連接的問題
