java中的任何類都從老祖宗Object中集成了equals方法,在編程實踐中應用使用equals方法判斷兩個對象是否相同的場景無處不在,所以我們在實現自己的類是必須重寫出一個優美的equals方法。
- 首先讓我們來看看java語言規范中對equals方法的說明,一個equals方法應當滿足如下幾個特性:
- 自反性,對任何一個非空的引用x,x.equals(x)必須返回true;
- 對稱性,對任何引用x和y來說,如果x.equals(y)返回true,那么y.equals(x)也必須返回true;
- 傳遞性,對任何引用x、y和z,如果x.equals(y)為true,y.equals(z)為true,那么x.equals(z)也必須為true;
- 一致性,如果x和y應用的對象沒有發生改變,那么對x.equals(y)的重復調用都應當返回同樣的值;
- 對任何非空引用x,e.equals(null)返回false。
根據上面的6個條件,我們在重寫一個equals方法時,可以遵循方法步驟:
- 將顯示參數命名為otherObject,稍后轉化為目標類型並命名為other;
- 檢查this和otherObject是否相同;
- 檢查otherObject是否為空,為空則返回false;
- 檢查this和otherObject類型是否相同;
- 將otherObject轉化為目標類型,並命名為other;
- 對類型中定義的屬性進行比較,如果是基礎數據類型使用==,如果是引用類型使用equals()。
其中第4條在父子類之間進行比較是需要注意。如果父類中定義的equals中的功能在子類中發生了變化,使用if(this.getClass() != otherObject)進行類型比較;如果父類中equals中的功能在子類中發生了變化,使用if(!(otherObject instanceof this.getClass()))進行比較。例如,Employee類中name和salary兩個屬性,Manager類繼承Employee,還擁有bonus屬性。Employee中重寫的equals方法比較name和salary是否相同,Manager繼承Employee的equals方法后並沒有再次進行重寫,那么再進行Employee和Manager類的對象的equals比較時,使用 if(!(otherObject instanceof this.getClass()))return false;如果Manager中除了比較name和salary外還要比較bonus,即Manager要重寫一個自己的equals方法,那么使用if(this.getClass()!=otherObject.getClass())return false;具體實現可以參考如下代碼:
public boolean equals(Object otherObject){ //a quick test to see if the object are identical if(this == otherObject){ return true; } //must return false if the explicit param is null if(otherObject == null){ return false; } //if the class des't match, they cannot be equal if(this.getClass() != otherObject.getClass()){ return false; } //now we the the otherObject is non-null Employee Employee other = (Employee)otherObject; //test whether the fields hava identical values return name.equals(other.name) &&salary == other.salary &&hireDay == other.hireDay; }
此處有一注意事項,在實現自己的equals方法時,如果聲明為public boolean equals(Employee otherObject),即顯示參數的類型不是Object類型,那么此方法不是繼承自Object對象,而是Employee自己定義的一個方法。從Object繼承的public boolean equals(Object otherObject)在java術語中交Overriding,自己定義的public boolean equals(Employee otherObject)叫Overloading。前者在運行期間動態綁定,后者在編譯期間靜態綁定。