在比較兩個類時,常見有兩種做法,一種是x.getClass() == y; 一種是x instanceof y,下面我們來比較這兩種做法的區別。
getClass()返回一個對象所屬的類
public static void main(String[] args) { Hero h1 = new Hero(null,10,2); Hero h2 = new Hero("zhang",10,2);
Superman s1 = new Superman("zhang");
System.out.println(h1.getClass());
System.out.println(h1.getClass() == h2.getClass());
System.out.println(h1.getClass() == s1.getClass());
System.out.println(s1.getClass() == h1.getClass());
}
返回:
class source.Hero
true
false
false
可以看到,getClass返回的是一個類名,也就是說只會在類名相同時返回true,不會判斷子類與父類的繼承關系。
instanceof比較一個對象是否是該類的實例
public static void main(String[] args) { Hero h1 = new Hero(null,10,2); Hero h2 = new Hero("zhang",10,2); Superman s1 = new Superman("zhang"); System.out.println((h1 instanceof Hero)); System.out.println(h2 instanceof Superman); System.out.println(s1 instanceof Hero); System.out.println(h1 instanceof Superman); }
返回:
true
false
true
false
可以看到,instanceof會判斷繼承關系,子對象 instanceof 父類 會返回true,父對象 instanceof 子類會返回 false。 可以理解為判斷兩個問題:你是這個類嗎? 你是這個類的派生類嗎?
equals方法:
public boolean equals(Object otherObject) { if(this == otherObject) return true; if(otherObject == null) return false; if(getClass() != otherObject.getClass()) return false; Hero other = (Hero)otherObject; return name.equals(other.name) && hp == other.hp &&damage == other.damage; }
equals方法具有下面特性:
1,自反性
2,對稱性
3,傳遞性
4,一致性
5,對於任意非空引用x,x.equals(null)應該返回false。
下面我們首先結合上面的內容討論對稱性。
father.equals(child)
這里的father與child具有相同的姓氏,血型,家族。如果在Father.equals中用instanceof檢測,會得到true。這意味着如果反過來調用:
child.equals(father)
也需要返回true。
應該這樣說:
1,如果子類擁有自己的相等概念,則對稱性需求將強制采用getClass進行檢測。 例如雇員和經理,對應的域相等就認為兩個對象相等;如果兩個經歷對應的名字薪水雇佣日期都相等,而獎金不相等,就認為他們不相同。
2,如果由超類決定相等的概念,那么可以用instanceof進行檢測,就可以在不同的子類對象之間進行相等的比較。例如經理是雇員的兒子類,假設使用雇員的ID作為相等的檢測條件,那么這個相等概念也適用於經理,此時可以用instanceof進行檢測,並且應該將Employee.equals方法聲明為final。
編寫完美equals方法的建議(來自CoreJava):
1,顯式參數命名為otherObject,稍后需要將它轉換成另一個叫做other的變量 這里參數一定是Object類型 否則不會產生Override
2,檢測this和otherObject是否引用同一個對象
if(this == otherObject) return true;
3,檢測otherObject是否為null。如果是null,則返回false
4,比較this和otherObject是否屬於同一個類。按照上面紅字的總結:如果equals的語義在每個子類中有所改變,就用getClass檢測:
if (getClass() != otherObject.getClass()) return false;
如果所有的子類都擁有統一的語義,就是用instanceof檢測
if (!(otherObject instanceof ClassName)) return false;
5,將otherObject轉換為相應的類類型變量:
ClassName other = (ClassName) otherObject;
6,現在開始對所有需要比較的域進行比較。使用 == 比較基本類型域, 使用equals比較對象域。
return field 1 == field2 && Objects.equals(field2,other.field2) &&....... ;
這里需要注意: 如果在兩個參數都為null時需要返回true,那么應該使用Objects.equals(1,2)
如果不能接受有參數為null,或者兩個參數不會為null,則使用a.equals(b) (當有一個參數為null時,a.equals(b)將會拋出NullPointerException)
如果在子類中重新定義equals,就要在其中包含調用super.equals(other)