一、概述
hashCode()方法定義在Object類中芯砸,其源碼為:
public native int hashCode();
由該方法的聲明可知:該方法為一個(gè)Native方法,返回值為int類型斋日,在Object類中并沒有具體的實(shí)現(xiàn)甸怕。為什么Object類中要定義一個(gè)這樣的方法缩多?它的作用是什么?
二峰尝、作用
對(duì)于集合類(容器類)的程序設(shè)計(jì)語言來說偏窝,基本都會(huì)用到hashCode(哈希值),在Java中,hashCode()方法的主要作用是是基于散列的集合正確存取囚枪,如HashSet派诬、HashMap、HashTable链沼。我們可以通過java.util.HashMap的中put方法的具體實(shí)現(xiàn):
public V put(K key, V value) {
if (key == null)
return putForNullKey(value);
int hash = hash(key.hashCode());
int i = indexFor(hash, table.length);
for (Entry<K,V> e = table[i]; e != null; e = e.next) {
Object k;
if (e.hash == hash && ((k = e.key) == key || key.equals(k))) {
V oldValue = e.value;
e.value = value;
e.recordAccess(this);
return oldValue;
}
}
modCount++;
addEntry(hash, key, value, i);
return null;
}
put方法是用來向HashMap中添加新的元素默赂,從put方法的具體實(shí)現(xiàn)可知,會(huì)先調(diào)用hashCode方法得到該元素的hashCode()方法得到該元素的哈希值括勺,HashMap在具體實(shí)現(xiàn)中會(huì)用一個(gè)table保存已經(jīng)存進(jìn)去的元素的hashcode值缆八,然后查看table中是否存在該hashCode值,如果存在則調(diào)用equals方法重新確定是否存在該元素疾捍,如果存在奈辰,則更新value值,否則將新的元素添加到HashMap中乱豆,不相同就散列其它的地址奖恰。從這里可以看出,hashCode方法的存在是為了減少equals方法的調(diào)用次數(shù)宛裕,從而提高程序效率瑟啃。說通俗一點(diǎn):Java中的hashCode方法就是根據(jù)一定的規(guī)則將與對(duì)象相關(guān)的信息(比如對(duì)象的存儲(chǔ)地址,對(duì)象的字段等)映射成一個(gè)數(shù)值揩尸,這個(gè)數(shù)值稱作為散列值蛹屿。
三、hashCode()方法和equals()方法
對(duì)于兩個(gè)對(duì)象:
- 如果調(diào)用equals方法得到的結(jié)果為true岩榆,則兩個(gè)對(duì)象的hashcode值必定相等错负;
- 如果equals方法得到的結(jié)果為false,則兩個(gè)對(duì)象的hashcode值不一定不同勇边;
- 如果兩個(gè)對(duì)象的hashcode值不等犹撒,則equals方法得到的結(jié)果必定為false;
- 如果兩個(gè)對(duì)象的hashcode值相等粒褒,則equals方法得到的結(jié)果未知油航。
四、原則
我們?cè)谠O(shè)計(jì)一個(gè)類的時(shí)候怀浆,有時(shí)候需要重寫equals()方法,比如String類就重寫了Object類的equals()方法谊囚,來比較兩個(gè)字符串是否相等。
但重寫equals()方法時(shí)执赡,有一個(gè)原則:那就是必須覆寫hashCode()方法镰踏,讓equals方法和hashCode方法始終在邏輯上保持一致性。
《Effective Java》一書對(duì)hashCode()方法有這樣一段描述:
- 在程序執(zhí)行期間沙合,只要equals方法的比較操作用到的信息沒有被修改奠伪,那么對(duì)這同一個(gè)對(duì)象調(diào)用多次,hashCode方法必須始終如一地返回同一個(gè)整數(shù);
- 如果兩個(gè)對(duì)象根據(jù)equals方法比較是相等的,那么調(diào)用兩個(gè)對(duì)象的hashCode方法必須返回相同的整數(shù)結(jié)果;
- 如果兩個(gè)對(duì)象根據(jù)equals方法比較是不等的绊率,則hashCode方法不一定得返回不同的整數(shù);
其中第一條可以這樣理解:設(shè)計(jì)hashCode()時(shí)最重要的因素就是:無論何時(shí)谨敛,對(duì)同一個(gè)對(duì)象調(diào)用hashCode()都應(yīng)該產(chǎn)生同樣的值。如果在講一個(gè)對(duì)象用put()添加進(jìn)HashMap時(shí)產(chǎn)生一個(gè)hashCdoe值滤否,而用get()取出時(shí)卻產(chǎn)生了另一個(gè)hashCode值脸狸,那么就無法獲取該對(duì)象了。所以如果你的hashCode方法依賴于對(duì)象中易變的數(shù)據(jù)藐俺,用戶就要當(dāng)心了炊甲,因?yàn)榇藬?shù)據(jù)發(fā)生變化時(shí),hashCode()方法就會(huì)生成一個(gè)不同的散列碼欲芹。因此卿啡,在設(shè)計(jì)hashCode方法和equals方法的時(shí)候,如果對(duì)象中的數(shù)據(jù)易變菱父,則最好在equals方法和hashCode方法中不要依賴于該字段颈娜。