1.何時需要重寫equals()
當一個類有自己特有的“邏輯相等”概念(不同於對象身份的概念)。
2.爲什麼改寫equals()的時候,總是要改寫hashCode()
兩個原則:
hashCode()的返回值和equals()的關係如下:
- 如果x.equals(y)返回“true”,那麼x和y的hashCode()必須相等。
- 如果x.equals(y)返回“false”,那麼x和y的hashCode()有可能相等,也有可能不等。
簡單的說,“相等的對象必須具有相等的散列碼”。
3.什麼是equals()與如何設計equals()
它是對象內容的比較。涵蓋內容比對象參閱值比較更豐富。什麼是對象參閱值比較:就是兩個對象的參閱變量的值的比較。值是一個數字,通過數字來鑑別不同對象的代號,這種默認的比較方式,在object對象中已有設計實現。
而對象內容的比較纔是設計equals()的真正目的。
參考《effective java》上equals的幾個特性:
- 對稱性:如果x.equals(y)返回是“true”,那麼y.equals(x)也應該返回是“true”。
- 反射性:x.equals(x)必須返回是“true”。
- 類推性:如果x.equals(y)返回是“true”,而且y.equals(z)返回是“true”,那麼z.equals(x)也應該返回是“true”。
- 還有一致性:如果x.equals(y)返回是“true”,只要x和y內容一直不變,不管你重複x.equals(y)多少次,返回都是“true”。
- 任何情況下,x.equals(null),永遠返回是“false”;x.equals(和x不同類型的對象)永遠返回是“false”。
設計步驟:
[1]使用instanceof操作符檢查“實參是否爲正確的類型”。
[2]對於類中的每一個“關鍵域”,檢查實參中的域與當前對象中對應的域值。
[2.1]對於非float和double類型的原語類型域,使用==比較;
[2.2]對於對象引用域,遞歸調用equals方法;
[2.3]對於float域,使用Float.floatToIntBits(afloat)轉換爲int,再使用==比較;
[2.4]對於double域,使用Double.doubleToLongBits(adouble) 轉換爲int,再使用==比較;
[2.5]對於數組域,調用Arrays.equals方法。
4.什麼是hashcode()與如何設計hashCode()
這
個函數返回的就是一個用來進行哈希操作的整型代號,請不要把這個代號和前面所說的參閱變量所代表的代號弄混了。後者不僅僅是個代號還具有在內存中才查找對 象的位置的功能。hashCode()所返回的值是用來分類對象在一些特定的收集對象中的位置。
設計步驟:
[1]把某個非零常數值,例如17,保存在int變量result中;
[2]對於對象中每一個關鍵域f(指equals方法中考慮的每一個域):
[2.1]boolean型,計算(f
? 0 : 1);
[2.2]byte,char,short型,計算(int);
[2.3]long型,計算(int)
(f ^ (f>>>32));
[2.4]float型,計算Float.floatToIntBits(afloat);
[2.5]double型,計算Double.doubleToLongBits(adouble)得到一個long,再執行[2.3];
[2.6]對象引用,遞歸調用它的hashCode方法;
[2.7]數組域,對其中每個元素調用它的hashCode方法。
[3]將上面計算得到的散列碼保存到int變量c,然後執行 result=37*result+c;
[4]返回result。
5.符合上面的原則的equals與hashcode的示例代碼
package com.zj.unit;
import java.util.Arrays;
public class Unit {
private short ashort;
private char achar;
private byte abyte;
private boolean abool;
private long along;
private float afloat;
private double adouble;
private Unit aObject;
private int[] ints;
private Unit[] units;
public boolean equals(Object o) {
if (!(o instanceof Unit))
return false;
Unit unit = (Unit) o;
return unit.ashort == ashort
&& unit.achar == achar
&& unit.abyte == abyte
&& unit.abool == abool
&& unit.along == along
&& Float.floatToIntBits(unit.afloat) == Float
.floatToIntBits(afloat)
&& Double.doubleToLongBits(unit.adouble) == Double
.doubleToLongBits(adouble)
&& unit.aObject.equals(aObject)
&& equalsInts(unit.ints)
&& equalsUnits(unit.units);
}
private boolean equalsInts(int[] aints) {
return Arrays.equals(ints, aints);
}
private boolean equalsUnits(Unit[] aUnits) {
return Arrays.equals(units, aUnits);
}
public int hashCode() {
int result = 17;
result = 37 * result + (int) ashort;
result = 37 * result + (int) achar;
result = 37 * result + (int) abyte;
result = 37 * result + (abool ? 0 : 1);
result = 37 * result + (int) (along ^ (along >>> 32));
result = 37 * result + Float.floatToIntBits(afloat);
long tolong = Double.doubleToLongBits(adouble);
result = 37 * result + (int) (tolong ^ (tolong >>> 32));
result = 37 * result + aObject.hashCode();
result = 37 * result + intsHashCode(ints);
result = 37 * result + unitsHashCode(units);
return result;
}
private int intsHashCode(int[] aints) {
int result = 17;
for (int i = 0; i < aints.length; i++)
result = 37 * result + aints[i];
return result;
}
private int unitsHashCode(Unit[] aUnits) {
int result = 17;
for (int i = 0; i < aUnits.length; i++)
result = 37 * result + aUnits[i].hashCode();
return result;
}
}