在Java編程中,Hashcode是一個非常重要的概念,它不僅是Java集合框架中對於散列表操作的基礎,而且還常常被用作對象的「身份證」,以區分不同對象之間的不同。本文將從多個方面深入探究Hashcode的原理及其應用。
一、Hashcode的原理
Hashcode,散列碼,是一種將任意大小的數據映射為固定大小數據的一種方法。簡單來說就是把任意長度的輸入(又叫做預映射, pre-image),通過散列算法,變換成固定長度的輸出(又叫做散列值, hash value, hash code,hash sums, checksum)。這個轉換的特點在於:
- 1、不同的輸入一定會產生不同的輸出
- 2、相同的輸入總是產生相同的輸出,但是不同的輸入也可能會產生相同的輸出
在Java中,Object類是所有類的父類。在Object中有一個hashCode()方法,其返回值是一個int型的整數。Object中默認的hashCode()方法生成的散列碼是根據對象的地址來生成的。也就是說只要不是同一個對象,其HashCode值不可能相同。所以在我們自定義的類中,如果沒有重寫hashCode()方法的話,使用該類創建的對象的hashcode值,都是根據其在內存中的地址而生成的。
二、Hashcode的重寫
在實際開發中,我們經常需要自定義類的實例作為Map的Key,為了在使用集合類時能夠正確操作,我們需要對自定義類的hashCode()進行重寫。理論上來說,如果兩個對象通過equals比較相等,那麼這兩個對象的hashCode()值也應該相等。
實現重寫
public class User { private String name; private int age; public User(String name, int age) { this.name = name; this.age = age; } // 為了方便,這裡不採用IDE自動生成的equals()方法 @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; User user = (User) o; return age == user.age && Objects.equals(name, user.name); } @Override public int hashCode() { return Objects.hash(name, age); } }
在上面的代碼中,我們重寫了hashCode()方法,使用Objects.hash()方法生成hash值。這個方案的缺點是Object.hash()底層實現是按位異或、位移運算等,稍微複雜,而且我們需要計算多個值,有時需要將其分別運算後再組合,增加了複雜度。
另一個簡單但性能好的方法是使用Objects.hash()重載方法,直接傳入需要計算的參數,該方法會自動進行異或、左移運算返回哈希值。
public int hashCode() { return Objects.hash(name, age); }
哈希衝突
在使用hashCode()方法時,一定要注意可能會遇到哈希衝突的情況。哈希衝突是指在存儲散列表的過程中,兩個對象計算出來的hashcode值相同。雖然這種情況出現的概率很小,但是如果出現,可能會導致散列表元素之間的對比耗費時間過長。
需要注意的是,在Java8之後,對於哈希衝突的處理方式改進了很多。當發現哈希表的某個桶中出現多個元素時,並不是直接去執行equals()操作判斷是否相等,而是先判斷兩個對象的哈希值是否相等,如果不相等直接視為不相等,如果相等再執行equals()操作。這個方式被稱為「鏈式存儲」或「開放地址技術」。
三、Hashcode的應用
1、作為Map的Key
將某個自定義的對象作為Map的Key時 hashCode()方法的重寫至關重要。作為Map的Key,對於hashCode()的要求是相同的對象始終生成相同的hash值。唯一的例外是,在Map中允許null作為Key,如果一個類的實例做Map的Key,那麼hashCode()方法至少要保證類的實例的成員變量都都參與hashCode()方法的計算,而且它們的值不會改變,否則會使hashCode()計算結果發生改變,導致在Map中無法正常獲取原本指向的對象。
2、作為對象標識符
在Java中,我們通常使用hashCode()方法生成對象的標識符。這樣可以方便地檢查兩個對象是否相等。例如,在hashCode()方法的實現中可以使用對象中的一個成員變量作為標識符。這個成員變量必須是一個唯一的標識,以便在需要時可以比較兩個對象。
3、作為算法基礎
除了前面提到的作用外,hashCode()方法還能作為某些算法的基礎。例如布隆過濾器算法就是基於hashCode()方法實現的。該算法的實現方式是創建一個長度為N的布爾數組,然後將一個元素計算出來的hash值對應到布爾數組的某個位置上,並將該位置設為true。這樣,如果另一個元素計算出來的hash值在布爾數組中對應的位置也為true,那麼即可判定該元素已經出現過了。
四、總結
Hashcode是Java編程中非常重要的概念之一。理解其原理並在需要時深入重寫hashCode()方法,能夠為Java工程師的編程能力提高很多,特別是在使用Java集合框架進行開發時。通過本文的闡述,我們相信Java工程師已經對Hashcode有了更深入的理解,並能更好地應用到開發中。
原創文章,作者:UHSB,如若轉載,請註明出處:https://www.506064.com/zh-hk/n/139920.html