以下是學習《Practical Java(重點版)》的筆記。
1. java提供了兩種數據類型:原生態和引用類型。原生態數據類型都有相應的包裝類對應。
如:int I = 5;//原生態類型
Integer j = new Integer(5);//引用類型
雖然這兩種方式存儲的數據都是在stack(棧)中並且都是32bits,但是存儲的意義是有區別的:前者是存儲的數字;而後者存儲的是引用(相當於是某個對象的地址),實際的對象是存儲在heap(堆)中。在效率上原生態類型要高點,但是原生態類型不能夠調用方法。
2. “==”和“equals”區別是很大的。
public class Test1 {
public static void main(String[] args) {
int a = 10;
int b = 10;
System.out.println(a == b);//輸出true
Integer ia = new Integer(10);
Integer ib = new Integer(10);
System.out.println(ia == ib);//輸出false
}
}
上述結果分析:== 只是淺比較,僅僅是比較兩邊是否一樣。對於原生態類型來說,僅僅是比較值。而對於對象引用來說,比較的是引用的地址是否一致。如果 要比較對象代表的值是否一致,請使用equals()方法。
使用“==”可以用來測試基本類型是否相等或者兩個引用是否指向同一個對象。使用“equals”來比較對象的值是否一樣。
3. 不要依賴默認的equals()方法,大多時候都是自己覆寫該方法,該方法是Object的方法。這是Object的方法:
public boolean equals(Object obj)
{
return this == obj;
}
明顯可以看到默認的equals方法比較的是兩個對象是否是引用同一對象,如果要確認兩個對象的值是否一樣,那麼就需要自己重寫該方法。
String重寫的equals()方法:先是比較兩個對象是否引用同一對象,再對比其值是否一樣。StringBuffer、StringBuilder沒有重寫equals方法。
String、StringBuffer、StringBuilder都是final類;
StringBuffer是線程安全的,效率低;
StringBuilder是線程非安全的,效率高。
4. 在覆寫equals方法時要慎重。當認爲Object的equals方法不能夠滿足要求時,可以覆寫equals方法。
5. 覆寫equals時,請優先使用getClass。
有這樣的一種說法:唯有相同的class產生出來的對象才相等,進一步可以說,如果兩個對象的class或者類型,則不可能相等。因此,在覆寫equals方法時,首先調用getClass來判斷兩個對象是否是同一class或者類型。
getClass()會返回某個對象的運行期類(runtime class)。
以下是反映繼承的getClass()調用關係:
public class Test1 {
public static void main(String[] args) {
A aB = new B();
A aC = new C();
System.out.println("aB = " + aB.getClass());//aB = class com.study2.B
System.out.println("aC = " + aC.getClass());//aC = class com.study2.C
System.out.println(aB.getClass() == aC.getClass());//false
}
}
class A {
}
class B extends A {
}
class C extends A {
}
從上面可以看出:儘管getClass是反映的引用的那個對象的類型,看“=”右邊的類型。
當我們要覆寫equals時,要考慮:1).父類是否覆寫了該方法,並且父類是否滿足了相等功能;2).相等是要什麼相等。
覆寫equals步驟:1)確定傳入的比較對象是否爲空;2)比較getClass是否一致;3)將對象向下轉換類型;4)比較要確定相等的屬性的值。
6. 調用super.equals()來喚醒父類的equals方法。在覆寫equals方法時,請檢查其父類的是否由equals方法,如果有的話,在子類覆寫equals時,請必須調用父類的equals方法,這樣才安全。不然的話,會破壞類的繼承體系。
7.在equals中慎重使用instanceof方法。
在equals中使用instanceof,當子類和父類進行比較的時候,特別要注意對稱相等性:即
subClass.equals(fathterClass);
fatherClass.equals(subClass);這兩個的結果有可能是不一致的。要儘量避免。
當我們使用equals時,有必要時知道代碼的equals的實現方式,其中判斷類的隸屬問題到底是instaceof還是getClass。
8. 覆寫equals的遵循規則
覆寫equals並不簡單,需要我們準確地定義爲什麼要這樣設計。
無論你選擇使用getClass()或instanceof來實現equals(),下面的規則適用於所有的equals()函數:
a.如果某個class 的兩個對象即使佔據不同的內存空間,也可被視爲「邏輯上相等」的話,那麼你得爲這個class 提供一個equals()。
b.請檢查是否等於this。
c.比較這個class 中的相關屬性(值域,fields),以判斷兩個對象是否相等。
d.如果有java.lang.Object 以外的任何父類實現了equals(), 那麼就應該調用super.equals()。
在equals()函數中面對getClass()和instanceof 進行取捨時,你要仔細斟酌以下問題:
a.如果只允許同一個class 所產生的對象被視爲相等,則通常使用getClass()。
b.只有在不得不「對子類對象與父類對象進行比較」的場合中,才使用instanceof,而且你應該明白這樣做帶來的可能問題和複雜性。
c.如果使用instanseof,而且子類和父類都實現有equals(),則一定要知道,這種比較不會展現出所謂的「對稱相等性」(symmetricequality)。