1. 哪些類型的數(shù)據(jù)會(huì)使用equals 方法淆党?
所有java 的所有的對象都可以使用該方法比較兩個(gè)對象是否相等唯咬。
2. equals 默認(rèn)比較的是對象的什么值段只?
不重寫時(shí)趣惠,equals 方法默認(rèn)比較的是對象的引用是否指向同一塊內(nèi)存地址
重寫equals 的目的是為了比較兩個(gè)對象的 value 值是相等
hashcode 的存在主要是為了查找的快捷性狸棍,因?yàn)樗怯脕泶_定對象在內(nèi)存中的存儲(chǔ)地址,比如我們需要將一個(gè)字段id 的值存放在內(nèi)存的0,1,2,3,4,5,6,7 這八個(gè)位置中味悄,那應(yīng)該把它存放在內(nèi)存中的哪個(gè)位置呢草戈,這時(shí)候就需要根據(jù)散列存儲(chǔ)結(jié)構(gòu)中計(jì)算對象的hashcode 值的方法:id%8 , 獲得該對象在內(nèi)存中的存放位置,但是這樣可能有多個(gè)不同對象計(jì)算的hashcode 相同侍瑟,所以唐片,可能同一個(gè)位置會(huì)存放多個(gè)的對象,所以說判斷兩個(gè)對象是否相等時(shí)涨颜,hashcode方法返回該對象的哈希碼值费韭, 會(huì)先通過hashcode 方法快速找到它在內(nèi)存中的存放位置,然后再通過equals 方法找到我們需要的對象庭瑰。
所以重寫equals 方法的同時(shí)星持,必須重寫hashcode 方法,因?yàn)楦鶕?jù)hashcode 的協(xié)定弹灭,相等的對象必須具有相等的哈希嗎钉汗。
hashCode用于返回對象的hash值,主要用于查找的快捷性鲤屡,因?yàn)閔ashCode也是在Object對象中就有的损痰,所以所有Java對象都有hashCode,在HashTable和HashMap這一類的散列結(jié)構(gòu)中酒来,都是通過hashCode來查找在散列表中的位置的卢未。
3. Java里面有==運(yùn)算符了,為什么還需要equals啊辽社?
equals和hashCode都是Object對象中的非final方法
equals()的作用是用來判斷兩個(gè)對象是否相等伟墙,在Object里面的定義是:
public boolean equals(Object obj) {
return (this == obj);
}
這里可以看到在實(shí)現(xiàn)我們自己的equals 之前, equals 等價(jià)于 ==
, 而==
運(yùn)算符判斷的是兩個(gè)對象是不是同一個(gè)對象滴铅,即他們的地址是否相等戳葵。而重寫equals 目的是比較兩個(gè)對象在邏輯上的相等,可以說是值相等汉匙,也可以說是內(nèi)容相等拱烁。
-
覆寫equals時(shí)有哪些準(zhǔn)則?
自反性: 對于任何非空引用值x, x.equals(x) 都應(yīng)該返回true
對稱性: 對于任何非空引用值 x 和 y噩翠, 當(dāng)且僅當(dāng)x.equals(y) 返回true 時(shí)戏自, y.equals(x) 才應(yīng)該返回true。
傳遞性:對于任何非空引用值 x伤锚、y 和 z擅笔,如果 x.equals(y) 返回 true, 并且 y.equals(z) 返回 true屯援,那么 x.equals(z) 應(yīng)返回 true猛们。
一致性:對于任何非空引用值x,y , 多次調(diào)用x.eqauls(y) 始終返回true或者始終返回false狞洋,前提是對象equals 比較中所用的額信息沒有被修改阅懦。
非空性:對于任何非空引用值x, x.equals(null)都應(yīng)該返回false
4. 什么場景下重寫equals 方法?
在我們的業(yè)務(wù)系統(tǒng)中判斷對象時(shí)有時(shí)候需要的不是一種嚴(yán)格意義上的相等徘铝,而是一種業(yè)務(wù)上的對象相等耳胎,即值相等或者說內(nèi)容相等。在這種情況下惕它,原生的equals方法就不能滿足我們的需求了怕午,所以我們需要重寫equals 方法來實(shí)現(xiàn)在比較兩個(gè)對象時(shí)只比較值相等即可。
5. 如何重寫equals 方法 和hashcode 方法淹魄?
@Override
public boolean equals(Object object) {
// //測試檢測的對象是否為空郁惜,是就返回false
if (object == null) {
return false;
}
//使用==操作符檢查“參數(shù)是否為這個(gè)對象的引用”:如果是對象本身,則直接返回甲锡,攔截了對本身調(diào)用的情況兆蕉,算是一種性能優(yōu)化。
if (object == this) {
return true;
}
//使用instanceof操作符檢查“參數(shù)是否是正確的類型”:如果不是缤沦,就返回false
// 在 equals() 中最好使用 getClass 進(jìn)行類型判斷,
if (!(object instanceof HashTest)) {
return false;
}
或者
//測試兩個(gè)對象所屬的類是否相同虎韵,否則返回false
if (this.getClass() != object.getClass()){
return false
}
//對object進(jìn)行類型轉(zhuǎn)換以便和類A的對象進(jìn)行比較
A other=(A)otherObject;
if (object.getI() == this.getI()) {
return true;
}
return false;
}
@Override
public int hashCode() {
return id.hashCode();
}
或者
@Override
public int hashCode() {
int hash = 17;
hash = hash * 31 + getName().hashCode();
return hash;
}
//或者有更簡單的方法
@Override
public int hashCode()
{
return Object.hashCode(屬性A,屬性B缸废,屬性C包蓝,……);
}
//關(guān)于hashCode()計(jì)算過程中驶社,為什么使用了數(shù)字31,主要有以下原因:
1测萎、使用質(zhì)數(shù)計(jì)算哈希碼亡电,由于質(zhì)數(shù)的特性,它與其他數(shù)字相乘之后硅瞧,計(jì)算結(jié)果唯一的概率更大份乒,哈希沖突的概率更小。
2腕唧、使用的質(zhì)數(shù)越大或辖,哈希沖突的概率越小,但是計(jì)算的速度也越慢四苇;31是哈希沖突和性能的折中,實(shí)際上是實(shí)驗(yàn)觀測的結(jié)果方咆。
3月腋、JVM會(huì)自動(dòng)對31進(jìn)行優(yōu)化:31 * i == (i << 5) – i
關(guān)于hashcode 的重寫請參考:http://www.importnew.com/25783.html
需要注意的地方:
- 我們在覆寫 equals() 方法時(shí),一般都是推薦使用 getClass 來進(jìn)行類型判斷瓣赂,不是使用 instanceof
原因:我們都清楚 instanceof 的作用是判斷其左邊對象是否為其右邊類的實(shí)例榆骚,返回 boolean 類型的數(shù)據(jù)。
可以用來判斷繼承中的子類的實(shí)例是否為父類的實(shí)現(xiàn)煌集。注意后面這句話:可以用來判斷繼承中的子類的實(shí)例是否為父類的實(shí)現(xiàn)妓肢,正是這句話在作怪。
具體例子請參考:http://wiki.jikexueyuan.com/project/java-enhancement/java-thirteen.html
- 覆蓋equals時(shí)一定要覆蓋hashCode
- equals函數(shù)里面一定要是Object類型作為參數(shù)
- equals方法本身不要過于智能苫纤,只要判斷一些值相等即可
特性:
如果兩個(gè)對象equals碉钠,那么它們的hashCode必然相等,
但是hashCode相等卷拘,equals不一定相等喊废。