ref:https://www.cnblogs.com/TinyWalker/p/4834685.html
--------------------
編寫equals方法的建議:
- 顯示參數命名為otherObject, 稍后轉化成other變量
public boolean equals(Object otherObject)
- 檢測this和otherObject是否是同一個對象的引用,是,返回true;
if(this==otherObject){
return true;
} - 檢測otherObject是否為null, 是, 返回false;
if(otherObject == null){
return false;
} - 比較this和otherObject是否屬於同一個類. 如果equals的語義在每個子類中有所改變,就使用getClass檢測:
if(getClass() != otherObject.getClass()){
return false;
}if(!(otherObject instanceof Employee)){
return false;
} - 將otherObject轉化為相對應的類型變量other
Employee other = (Employee)otherObject;
- 對所需要的比較的數據域進行比較. 如果是基本數據類型,使用a==b比較; 如果是對象比較,調用Objects.equals(a, b)進行比較
return Objects.equals(name, other.name) && salary == other.salary && Objects.equals(hireDay, other.hireDay);
整個流程可以參照例1;
例1:雇員對象比較
如果兩個雇員對象的姓名, 薪水和雇佣一樣,就認為它們相等.重寫equals方法如下:
private String name;
private double salary;
private Date hireDay;
...
@Override
public boolean equals(Object obj) {
// 如果為同一對象的不同引用,則相同
if (this == obj) {
return true;
}
// 如果傳入的對象為空,則返回false
if (obj == null) {
return false;
}
// 如果兩者屬於不同的類型,不能相等
if (getClass() != obj.getClass()) {
return false;
}
// 類型相同, 比較內容是否相同
Employee other = (Employee) obj;
return Objects.equals(name, other.name) && salary == other.salary && Objects.equals(hireDay, other.hireDay);
}
}
注意,比較通過Objects中靜態函數equals比較兩個對象是否相等.該方法源碼如下:
return (a == b) || (a != null && a.equals(b));
}
這樣,當兩個對象都為null時,返回true,例如,兩個Employee對象的name都為null, 返回true; 如果第一個對象不為null,則調用a.equals(Object obj)方法
常見equals方法實現錯誤
1-未使用@override對覆蓋超類的方法進行標記.
public boolean equals(Employee other) {
return Objects.equals(name, other.name) && salary ==other.salary && Objects.equals(hireDay, other.hireDay);
}
這個方法聲明的顯示參數類型是Employee. 其結果並沒有覆蓋Object中的equals方法,而是定義了一個完全無關的方法.為了避免發生類型錯誤,可以使用@override對覆蓋超類的方法進行標記.
2-沒有同時override hashcode()函數
object對象中的 public boolean equals(Object obj),對於任何非空引用值 x 和 y,當且僅當 x 和 y 引用同一個對象時,此方法才返回 true;
注意:當此方法被重寫時,通常有必要重寫 hashCode 方法,以維護 hashCode 方法的常規協定,該協定聲明相等對象必須具有相等的哈希碼。如下:
(1)當obj1.equals(obj2)為true時,obj1.hashCode() == obj2.hashCode()必須為true
(2)當obj1.hashCode() == obj2.hashCode()為false時,obj1.equals(obj2)必須為false
如果不重寫equals,那么比較的將是對象的引用是否指向同一塊內存地址,重寫之后目的是為了比較兩個對象的value值是否相等。特別指出利用equals比較八大包裝對象
(如int,float等)和String類(因為該類已重寫了equals和hashcode方法)對象時,默認比較的是值,在比較其它自定義對象時都是比較的引用地址
hashcode是用於散列數據的快速存取,如利用HashSet/HashMap/Hashtable類來存儲數據時,都是根據存儲對象的hashcode值來進行判斷是否相同的。
這樣如果我們對一個對象重寫了euqals,意思是只要對象的成員變量值都相等那么euqals就等於true,但不重寫hashcode,那么我們再new一個新的對象,
當原對象.equals(新對象)等於true時,兩者的hashcode卻是不一樣的,由此將產生了理解的不一致,如在存儲散列集合時(如Set類),將會存儲了兩個值一樣的對象,
導致混淆,因此,就也需要重寫hashcode()
舉例說明:
public override bool Equals(object obj) { if (!(obj is BalanceSheetReport expect)) return false; return this.EndSum == expect.EndSum && this.PreSum == expect.PreSum && this.SequenceId == expect.SequenceId && this.ProjectId == expect.ProjectId; } public override int GetHashCode() { return this.PreSum.GetHashCode() ^ this.EndSum.GetHashCode() ^ this.SequenceId.GetHashCode() ^ this.ProjectId.GetHashCode(); }