Practical Java(重點版)之對象與相等性

 以下是學習《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)。

發佈了42 篇原創文章 · 獲贊 0 · 訪問量 1萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章