Object.hashCode()与Object.equals()
【README】
本文旨在po出 hashCode , equals的api描述,以加深理解;
本文翻譯自 jdk 文檔;
【1】Object.hashCode()
1)介紹:返回對(duì)象的哈希碼值。支持此方法是為了有利于哈希表,例如由 java.util.HashMap 提供的哈希表。
在 Java 應(yīng)用程序執(zhí)行期間,只要在同一個(gè)對(duì)象上多次調(diào)用它,hashCode 方法必須始終返回相同的整數(shù),前提是對(duì)象上的 equals 比較中使用的信息沒有被修改。該整數(shù)不需要從應(yīng)用程序的一次執(zhí)行到同一應(yīng)用程序的另一次執(zhí)行保持一致。
hashCode方法需要遵守的約定:如果根據(jù) equals(Object) 方法兩個(gè)對(duì)象相等,則對(duì)兩個(gè)對(duì)象中的每一個(gè)調(diào)用 hashCode 方法必須產(chǎn)生相同的整數(shù)結(jié)果(*干貨)。
如果根據(jù) equals(Object) 方法兩個(gè)對(duì)象不相等,則不需要對(duì)這兩個(gè)對(duì)象中的每一個(gè)調(diào)用 hashCode 方法必須產(chǎn)生不同的整數(shù)結(jié)果。但是,程序員應(yīng)該意識(shí)到為不相等的對(duì)象生成不同的整數(shù)結(jié)果可能會(huì)提高哈希表的性能。
盡可能實(shí)用,類 Object 定義的 hashCode 方法確實(shí)為不同的對(duì)象返回不同的整數(shù)。 (這通常通過將對(duì)象的內(nèi)部地址轉(zhuǎn)換為整數(shù)來實(shí)現(xiàn),但 Java? 編程語(yǔ)言不需要這種實(shí)現(xiàn)技術(shù)。)
補(bǔ)充: 可以看下 equals(), System.identityHashCode()
【1.1】String.hashCode()
返回此字符串的哈希碼。 String 對(duì)象的哈希碼計(jì)算如下
??????? s[0]*31^(n-1) + s[1]*31^(n-2) + ... + s[n-1]? ?????
使用 int 算術(shù),其中 s[i] 是字符串的第 i 個(gè)字符,n 是字符串的長(zhǎng)度,^ 表示求冪。 (空字符串的哈希值為零。)
返回:此對(duì)象的哈希碼值。
字符串底層是字符數(shù)組存儲(chǔ)的,以字符串 aaa為例,存儲(chǔ)結(jié)構(gòu)為 ['a', 'a', 'a'] ,字符a的 ASCII 為97,則hash值計(jì)算步驟如下:
i 取值 0, 1, 2;初始時(shí), h=hash=0;
| i | val[i] | h |
| 0 | 97 | 97 |
| 1 | 97 | 31*97+97 => 3104 |
| 2 | 97 | 31*3104+97=> 96321???? |
所以字符串 aaa的hash值等于? 96321 。
我們令 vi = val[i],則以后如下規(guī)則:
h0 = v0;
h1=31*v0+v1;
h2=31* [31*v0 + v1] + v2;
...
通過歸納法,我們可以得出字符串的hash值的計(jì)算公式為:
hn = 31^n * v0 + 31^n-1 * v1 + ...... + 31 * vn-1 + 31^0 * vn;? 其中,vn表示字符串的第n個(gè)字符,n從0開始;
所以 字符串 "aaa" 的hash值 h2 = 31^2 * 97 + 31 * 97 + 97 = 96321 ;
【2】Object.equals ()
1)介紹:指示其他某個(gè)對(duì)象是否“等于”這個(gè)對(duì)象。
2)equals 方法在非空對(duì)象引用上實(shí)現(xiàn)等價(jià)關(guān)系:
- 它是自反的:對(duì)于任何非空引用值 x,x.equals(x) 應(yīng)該返回 true。
- 它是對(duì)稱的:對(duì)于任何非空引用值 x 和 y,當(dāng)且僅當(dāng) y.equals(x) 返回 true 時(shí),x.equals(y) 才應(yīng)返回 true。
- 它是可傳遞的:對(duì)于任何非空引用值 x、y 和 z,如果 x.equals(y) 返回 true 并且 y.equals(z) 返回 true,那么 x.equals(z) 應(yīng)該返回 true。
- 它是一致的:對(duì)于任何非空引用值 x 和 y,x.equals(y) 的多次調(diào)用始終返回 true 或始終返回 false,前提是對(duì)象的 equals 比較中使用的信息沒有被修改。
對(duì)于任何非空引用值 x,x.equals(null) 應(yīng)返回 false。
Object 類的 equals 方法實(shí)現(xiàn)了對(duì)象上最有區(qū)別的可能等價(jià)關(guān)系;也就是說,對(duì)于任何非空引用值 x 和 y,當(dāng)且僅當(dāng) x 和 y 引用同一個(gè)對(duì)象(x == y 的值為 true)時(shí),此方法才返回 true。
請(qǐng)注意,每當(dāng)重寫此方法時(shí),通常都需要重寫 hashCode 方法,以維護(hù) hashCode 方法的一般約定,即相等的對(duì)象必須具有相等的哈希碼。
補(bǔ)充:也可以看看: hashCode(), java.util.HashMap
【3】System.identityHashCode(Object x)
1)介紹:為給定對(duì)象返回與默認(rèn)方法 hashCode() 返回的相同的哈希碼,無(wú)論給定對(duì)象的類是否覆蓋 hashCode()。 空引用的哈希碼為零。
【4】HashMap.hash(Object key)?
static final int hash(Object key) {int h;return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);}計(jì)算 key.hashCode() 并將散列的較高位(異或)傳播到較低位。
由于該表使用二次冪掩碼,因此僅在當(dāng)前掩碼之上位變化的散列集將始終發(fā)生沖突。 (眾所周知的例子是在小表中保存連續(xù)整數(shù)的浮點(diǎn)鍵集。)
因此,我們應(yīng)用了一種將較高位的影響向下傳播的變換。 位擴(kuò)展的速度、效用和質(zhì)量之間存在權(quán)衡。 因?yàn)樵S多常見的哈希集已經(jīng)合理分布(因此不會(huì)從傳播中受益),并且因?yàn)槲覀兪褂脴鋪硖幚?bin 中的大量沖突,所以我們只是以最便宜的方式對(duì)一些移位的位進(jìn)行異或以減少系統(tǒng)損失, 以及合并最高位的影響,否則由于表邊界而永遠(yuǎn)不會(huì)在索引計(jì)算中使用。
總結(jié)
以上是生活随笔為你收集整理的Object.hashCode()与Object.equals()的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: nginx学习小结
- 下一篇: (转)如何保障微服务架构下的数据一致性?