日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

hashcode()和hash()

發布時間:2025/3/21 编程问答 41 豆豆
生活随笔 收集整理的這篇文章主要介紹了 hashcode()和hash() 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

1 為什么有hashcode()方法

equals()和hashcode()這兩個方法都是從object類中繼承過來的。

hashcode() 方法,在object類中定義如下:

public native int hashCode();

native說明是一個本地方法,它的實現是根據本地機器相關的。當然我們可以在自己寫的類中覆蓋hashcode()方法,比如String、Integer、Double。。。。等等這些類都是覆蓋了hashcode()方法的。
例如String類中:就是以31為權,每一位為字符的ASCII值進行運算,用自然溢出來等效取模。(為什么取31?主要是因為31是一個奇質數,所以31i = 32i - i = (i << 5) - i,這種位移與減法結合的計算相比一般的運算快很多)。

public int hashCode() {int h = hash;if (h == 0 && value.length > 0) {char val[] = value;for (int i = 0; i < value.length; i++) {h = 31 * h + val[i];}hash = h;}return h;}

Integer類的:

public static int hashCode(int value) {return value;}

Double類的

public static int hashCode(double value) {long bits = doubleToLongBits(value);return (int)(bits ^ (bits >>> 32));}

hashCode對于List集合、數組而言,他就是一個累贅,但是對HashMap、HashSet、HashTable而言,它變得異常重要。hashCode是用來在散列存儲結構中確定對象的存儲地址的。
考慮一種情況,當向集合中插入對象時,如何判別在集合中是否已經存在該對象了?(注意:集合中不允許重復的元素存在)也許大多數人都會想到調用equals方法來逐個進行比較,這個方法確實可行。但是如果集合中已經存在一萬條數據或者更多的數據,如果采用equals方法去逐一比較,效率必然是一個問題。此時hashCode方法的作用就體現出來了,當集合要添加新的對象時,先調用這個對象的hashCode方法,得到對應的hashcode值,實際上在HashMap的具體實現中會用一個table保存已經存進去的對象的hashcode值,如果table中沒有該hashcode值,它就可以直接存進去,不用再進行任何比較了;如果存在該hashcode值, 就調用它的equals方法與新元素進行比較,相同的話就不存了,不相同就散列其它的地址,所以這里存在一個沖突解決的問題,這樣一來實際調用equals方法的次數就大大降低了,說通俗一點:Java中的hashCode方法就是根據一定的規則將與對象相關的信息(比如對象的存儲地址,對象的字段等)映射成一個數值,這個數值稱作為散列值。

2 hashCode與equals

如果x.equals(y)返回“true”,那么x和y的hashCode()必須相等。
如果x.equals(y)返回“false”,那么x和y的hashCode()有可能相等,也有可能不等。

3 HashMap中的hash()

hashmap中要找到某個元素,需要根據key的hash值來求得對應數組中的位置.
key的hash值高16位不變,低16位與高16位異或作為key的最終hash值。(h >>> 16,表示無符號右移16位,高位補0,任何數跟0異或都是其本身,因此key的hash值高16位不變。)

static final int hash(Object key) {int h;return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16); }

為什么要這么干呢? 這個與HashMap中table下標的計算有關。

n = table.length; index = (n-1) & hash;

當 length 總是 2 的倍數時,h & (length-1)將是一個非常巧妙的設計:
假設 h=5,length=16, 那么 h & length - 1 將得到 5;
如果 h=6,length=16, 那么 h & length - 1 將得到 6 ……
如果 h=15,length=16, 那么 h & length - 1 將得到 15;
但是當 h=16 時 , length=16 時,那么 h & length - 1 將得到 0 了;
當 h=17 時 , length=16 時,那么 h & length - 1 將得到 1 了……
這樣保證計算得到的索引值總是位于 table 數組的索引之內。

HashMap的初始大小和擴容都是以2的次方來進行的,換句話說length-1換成二進制永遠是全部為1,比如容量為16,則length-1為1111,大家知道位運算&的規則是兩個1才得1,遇0得0,也就是說length-1中的某一位為1,則對應位置的計算結果只取決于h中的對應位置(h中對應位取0,則對應位結果為0,h對應位取1,則對應位結果為1。這樣就有兩個結果),但是如果length-1中某一位為0,則不論h中對應位的數字為幾,對應位結果都是0,這樣就讓兩個h取到同一個結果,這就是hash沖突了,恰恰length-1又是全部為1的數,所以結果自然就將hash沖突最小化了
總之:
1.length(2的整數次冪)的特殊性導致了length-1的特殊性(二進制全為1)

2.位運算快于十進制運算,hashmap擴容也是按位擴容

4 HashTable中的hash()

int hash = key == null ? 0 : key.hashCode() & 0x7FFFFFFF; int index = hash % table.length;

5 ConcurrentHashMap中的hash()

// 用于和負數hash值進行 & 運算,將其轉化為正數(絕對值不相等),Hashtable中定位hash桶也有使用這種方式來進行負數轉正數static final int HASH_BITS = 0x7fffffff;int hash = spread(key.hashCode());int index = (n - 1) & hash;static final int spread(int h) {return (h ^ (h >>> 16)) & HASH_BITS;}



作者:時間的禮盒
鏈接:https://www.jianshu.com/p/b9558ad35f70
來源:簡書
簡書著作權歸作者所有,任何形式的轉載都請聯系作者獲得授權并注明出處。

總結

以上是生活随笔為你收集整理的hashcode()和hash()的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。