Java hashCode() 方法詳細(xì)解讀
1.WHY hashCode()?
集合Set中的元素是無序不可重復(fù)的,那判斷兩個元素是否重復(fù)的依據(jù)是什么呢? “比較對象是否相等當(dāng)然用Object.equal()了”,某猿如是說。但是,Set中存在大量對象,后添加到集合Set中的對象元素比較次數(shù)會逐漸增多,大大降低了程序運行效率。 Java中采用哈希算法(也叫散列算法)來解決這個問題,將對象(或數(shù)據(jù))依特定算法直接映射到一個地址上,對象的存取效率大大提高。這樣一來,當(dāng)含有海量元素的集合Set需要添加某元素(對象)時,先調(diào)用這個元素的hashCode(),就能一下子定位到此元素實際存儲位置,如果這個位置沒有元素,說明此對象時第一次存儲到集合Set, 直接將此對象存儲在此位置上;若此位置有對象存在,調(diào)用equal()看看這兩個對象是否相等,相等就舍棄此元素不存,不等則散列到其他地址。
2.HOW use hashCode()?
Java語言對猿設(shè)計equal()有五個必須遵循的要求。
對稱性。若 a.equal(b) 返回”true”, 則 b.equal(a) 也必須返回 “true”.
反射性。a.equal(a) 必須返回”true”.
傳遞性。若a.equal(b) 返回 “true”, 且 b.equal(c)返回 “true”, 則c.equal(a)必返回”true”.
一致性。若a.equal(b) 返回”true”, 只要a, b內(nèi)容不變,不管重復(fù)多少次a.equal(b)必須返回”true”.
任何情況下,a.equals(null),永遠(yuǎn)返回是“false”;a.equals(和a不同類型的對象)永遠(yuǎn)返回是“false”.
hashCode()的返回值和equals()的關(guān)系.
如果a.equals(b)返回“true”,那么a和b的hashCode()必須相等。
如果a.equals(b)返回“false”,那么a和b的hashCode()有可能相等,也有可能不等。
下面是一個例子。在實際的軟件開發(fā)中,最好重寫這兩個方法。
public class Employee {
int employeeId;
String name;
// other methods would be in here
@Override
public boolean equals(Object obj)
{
if(obj==this)
return true;
Employee emp=(Employee)obj;
if(employeeId.equals(emp.getEmployeeId()) && name==emp.getName())
return true;
return false;
}
@Override
public int hashCode() {
int hash = 1;
hash = hash * 17 + employeeId;
hash = hash * 31 + name.hashCode();
return hash;
}
}
3.下面著重介紹一下常用類的hashCode()實現(xiàn)方法。
String類的hasCode()
public int hashCode() {
int h = hash;
if (h == 0) {
int off = offset;
char val[] = value;
int len = count;
for (int i = 0; i < len; i++) {
h = 31*h + val[off++];
}
hash = h;
}
return h;
}
這段代碼最有意思的還是hash的實現(xiàn)方法了。最終計算的hash值為:
s[0]31n-1 + s[1]31n-2 + … + s[n-1]
s[i]是string的第i個字符,n是String的長度。那為什么這里用31,而不是其它數(shù)呢?
31是個奇素數(shù),如果乘數(shù)是偶數(shù),并且乘法溢出的話,信息就會丟失,因為與2相乘等價于移位運算。使用素數(shù)的好處并不是很明顯,但是習(xí)慣上都使用素數(shù)來計算散列結(jié)果。31有個很好的特性,就是用移位和減法來代替乘法,可以得到更好的性能:31*i==(i<<5)-i?,F(xiàn)在的VM可以自動完成這種優(yōu)化。(From Effective Java)
Object類的hasCode()
Object類中hashCode()是一個Native方法。Native方法如何調(diào)用?
public native int hashCode();
Object類的Native方法類可在這里找到。 深入分析請看另外一篇博客
static JNINativeMethod methods[] = {
{"hashCode", "()I", (void *)&JVM_IHashCode},
{"wait", "(J)V", (void *)&JVM_MonitorWait},
{"notify", "()V", (void *)&JVM_MonitorNotify},
{"notifyAll", "()V", (void *)&JVM_MonitorNotifyAll},
{"clone", "()Ljava/lang/Object;", (void *)&JVM_Clone},
};
源代碼包括getClass()(See line58)等, hashCode()(See line43)被定義為一個指向JVM_IHashCode指針。
jvm.cpp中定義了JVM_IHashCode(line 504)函數(shù), 此函數(shù)里調(diào)用ObjectSynchronizer::FastHashCode,其定在 synchronizer.cpp, 可參考576行的FastHashCode 和 530行的 get_next_hash 的實現(xiàn)。
相關(guān)文章
Spring Boot Admin Server管理客戶端過程詳解
這篇文章主要介紹了Spring Boot Admin Server管理客戶端過程詳解,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下2020-03-03
Java 如何實現(xiàn)POST(x-www-form-urlencoded)請求
這篇文章主要介紹了Java 實現(xiàn)POST(x-www-form-urlencoded)請求,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2021-10-10
使用postman傳遞list集合后臺springmvc接收
這篇文章主要介紹了使用postman傳遞list集合后臺springmvc接收的操作,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2021-08-08
Java中@RequiredArgsConstructor注解的基本用法
這篇文章主要介紹了Java中@RequiredArgsConstructor注解的基本用法,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2024-09-09
Java多線程中不同條件下編寫生產(chǎn)消費者模型方法介紹
這篇文章主要介紹了Java多線程中不同條件下編寫生產(chǎn)消費者模型方法介紹,介紹了生產(chǎn)消費者模型,然后分享了相關(guān)代碼示例,具有一定參考價值,需要的朋友可以了解下。2017-11-11
一文詳解Java?etcd的應(yīng)用場景及編碼實戰(zhàn)
etcd?是一個高度一致的分布式鍵值存儲系統(tǒng)。本文旨在幫助大家理解etcd,從宏觀角度俯瞰etcd全局,掌握etcd的基本操作技能,需要的可以參考一下2022-08-08

