1.hashcode是用來(lái)查找的,如果你學(xué)過(guò)數(shù)據(jù)結(jié)構(gòu)就應(yīng)該知道,在查找和排序這一章有
例如內(nèi)存中有這樣的位置
0 1 2 3 4 5 6 7
而我有個(gè)類(lèi),這個(gè)類(lèi)有個(gè)字段叫ID,我要把這個(gè)類(lèi)存放在以上8個(gè)位置之一,如果不用hashcode而任意存放,那么當(dāng)查找時(shí)就需要到這八個(gè)位置里挨個(gè)去找,或者用二分法一類(lèi)的算法。
但如果用hashcode那就會(huì)使效率提高很多。
我們這個(gè)類(lèi)中有個(gè)字段叫ID,那么我們就定義我們的hashcode為ID%8,然后把我們的類(lèi)存放在取得得余數(shù)那個(gè)位置。比如我們的ID為9,9除8的
余數(shù)為1,那么我們就把該類(lèi)存在1這個(gè)位置,如果ID是13,求得的余數(shù)是5,那么我們就把該類(lèi)放在5這個(gè)位置。這樣,以后在查找該類(lèi)時(shí)就可以通過(guò)ID除
8求余數(shù)直接找到存放的位置了。
2.但是如果兩個(gè)類(lèi)有相同的hashcode怎么辦那(我們假設(shè)上面的類(lèi)的ID不是唯一的),例如9除以8和17除以8的余數(shù)都是1,那么這是不是合法的,回答是:可以這樣。那么如何判斷呢?在這個(gè)時(shí)候就需要定義 equals了。
也就是說(shuō),我們先通過(guò) hashcode來(lái)判斷兩個(gè)類(lèi)是否存放某個(gè)桶里,但這個(gè)桶里可能有很多類(lèi),那么我們就需要再通過(guò) equals 來(lái)在這個(gè)桶里找到我們要的類(lèi)。
那么。重寫(xiě)了equals(),為什么還要重寫(xiě)hashCode()呢?
想想,你要在一個(gè)桶里找東西,你必須先要找到這個(gè)桶啊,你不通過(guò)重寫(xiě)hashcode()來(lái)找到桶,光重寫(xiě)equals()有什么用啊
hashCode()是用來(lái)產(chǎn)生哈希瑪?shù)模,斒怯脕?lái)在散列存儲(chǔ)結(jié)構(gòu)中確定對(duì)象的存儲(chǔ)地址的,(這一段在 Java編程思想
中講的很清楚的)象util包中的 帶 hash 的集合類(lèi)都是用這種存儲(chǔ)結(jié)構(gòu) :HashMap,HashSet,
他們?cè)趯?duì)象存儲(chǔ)時(shí)(嚴(yán)格說(shuō)是對(duì)象引用),需要確定他們的地址吧,
而HashCode()就是這個(gè)用途的,一般都需要重新定義它的,因?yàn)槟J(rèn)情況下,由 Object 類(lèi)定義的 hashCode
方法會(huì)針對(duì)不同的對(duì)象返回不同的整數(shù),這一般是通過(guò)將該對(duì)象的內(nèi)部地址轉(zhuǎn)換成一個(gè)整數(shù)來(lái)實(shí)現(xiàn)的,現(xiàn)在舉個(gè)例子來(lái)說(shuō), 就拿HashSet來(lái)說(shuō)
,在將對(duì)象存入其中時(shí),通過(guò)被存入對(duì)象的 hashCode() 來(lái)確定對(duì)象在 HashSet
中的存儲(chǔ)地址,通過(guò)equals()來(lái)確定存入的對(duì)象是否重復(fù),hashCode()
,equals()都需要自己重新定義,因?yàn)閔ashCode()默認(rèn)前面已經(jīng)說(shuō)啦,而equals()
默認(rèn)是比較的對(duì)象引用,你現(xiàn)在想一下,如果你不定義equals()的話,那么同一個(gè)類(lèi)產(chǎn)生的兩個(gè)內(nèi)容完全相同的對(duì)象都可以存入Set,因?yàn)樗麄兪峭ㄟ^(guò)
equals()來(lái)確定的,這樣就使得HashSet 失去了他的意義,看一下下面這個(gè):
import java.util.*;
/**
*類(lèi)說(shuō)明
* @author shellfeng E-mail:lsf830804@yahoo.com.cn
* @version 1.0
*
*/
public class Test {
public static void main(String[] args) {
HashSet set = new HashSet();
for (int i = 0; i <= 3; i++){
set.add(new Demo1(i,i));
}
System.out.println(set);
set.add(new Demo1(1,1));
System.out.println(set);
System.out.println(set.contains(new Demo1(0,0)));
System.out.println(set.add(new Demo1(1,1)));
System.out.println(set.add(new Demo1(4,4)));
System.out.println(set);
}
private static class Demo1 {
private int value;
private int id;
public Demo1(int value,int id) {
this.value = value;
this.id=id;
}
public String toString() {
return " value = " + value;
}
public boolean equals(Object o) {
Demo1 a = (Demo1) o;
return (a.value == value) ? true : false;
}
public int hashCode() {
return id;
}
}
}
你分別注釋掉hashCode()和 equals()來(lái)比較一下他們作用就可以拉,關(guān)鍵要自己動(dòng)手看看比較的結(jié)果你就可以記得很清楚啦
結(jié)果:
[ value = 2, value = 1, value = 3, value = 0]
[ value = 2, value = 1, value = 3, value = 0]
true
false
true
[ value = 2, value = 4, value = 1, value = 3, value = 0]
注釋掉hashCode()
[ value = 1, value = 0, value = 2, value = 3]
[ value = 1, value = 0, value = 1, value = 2, value = 3]
false
true
true
[ value = 1, value = 0, value = 1, value = 2, value = 3, value = 4, value = 1]
注釋掉equals()
[ value = 2, value = 1, value = 3, value = 0]
[ value = 2, value = 1, value = 1, value = 3, value = 0]
false
true
true
[ value = 2, value = 4, value = 1, value = 1, value = 1, value = 3, value = 0]
hashCode()方法使用來(lái)提高M(jìn)ap里面的搜索效率的,Map會(huì)根據(jù)不同的hashCode()來(lái)放在不同的桶里面,Map在搜索一個(gè)對(duì)象的時(shí)候先
通過(guò)hashCode()找到相應(yīng)的桶,然后再根據(jù)equals()方法找到相應(yīng)的對(duì)象.要正確的實(shí)現(xiàn)Map里面查找元素必須滿足一下兩個(gè)條件:
(1)當(dāng)obj1.equals(obj2)為true時(shí)obj1.hashCode() == obj2.hashCode()必須為true
(2)當(dāng)obj1.hashCode() == obj2.hashCode()為false時(shí)obj.equals(obj2)必須為false