effective java讀書筆記——對於所有對象都通用的方法

來源:互聯網
上載者:User

標籤:

Java中的所有類都繼承自Object類,Object類中有許多通用的方法,這一章要討論的是:對於Object類中的通用方法,我們的類要不要繼承,以及繼承時需要注意的事項。

第1條:equals(),覆蓋時請遵守通用約定

首先看一下不需要覆蓋的情況:

1.類的每個執行個體本質上是唯一的。(比如Static的,單例的等等),這樣不需要特意覆蓋equals方法,用Object類的equals()方法就足夠了

2.不關心類是否實現了“邏輯相等”的測試功能。我們用equals的目的就是判斷兩個對象是否是“邏輯相等”的,比如String類的值是否相等。如果這個類並不需要這個功能,那麼我們自然沒必要覆蓋equals()方法。

3.超類已經覆蓋了equals()方法,且從超類繼承過來的行為對子類也是合適的。

4.有一種“值類”不需要覆蓋,即執行個體受控類,確保“每個值之多隻存在一個對象”,枚舉類型就是這種類,對於這樣的類,邏輯相等與對象相等是一回事,所以不需要覆蓋equals()方法

那麼什麼時候需要覆蓋呢?

如果類有自己特有的“邏輯相等”的概念,而且父類還沒有覆蓋equals以實現期望的行為,這時我們就需要覆蓋equals()方法了。這通常屬於“值類”。值類通常是一個只表示值的類,如Integer,程式員在用equals比較時僅僅希望知道它們的值是否相等,而關心它們是否指向同一個對象。

equals方法需要實現“等價關係”,包含四個方面:

1.自反性。x.equals(x)必須始終返回true.

2.對稱性。如果x.equals(y)=true,那麼y.equals(x)也必須為true.

3.傳遞性。如果有x.equals(y)= true,y.equals(z) = true,那麼也必有x.quals(z) = true.

4.一致性。只要值沒被修改,那麼多次調用x.equals(y)的值應該始終相等。

下面舉一些違反了這4條的例子。

違反自反性:這種一般很少,因為這一條僅僅要求對象等於自身。如果違反了的話,假設你把一個對象加到一個集合裡,然後查詢,該集合的contains方法會告訴你集合中不存在這個元素。

違反對稱性:考慮下面的類,它實現了一個區分大小寫字串,但比較時不考慮大小寫。

public final class CaseInsensitiveString{    private final String s;    ...    public boolean equals(Object o){        if( o instanceof CaseInsentiveString){            return s.equalsIgnoreCase( ((CaseInsentiveString) o).s);        if( o instanceof String)         //考慮了與普通String類的比較            return s.equalsIgnoreCase((String) o);        return false;    }}    

看上去考慮的很好,比較時,考慮了傳入的對象是本類和String類的情況。但是,假設我們有兩個對象:
CaseInsensitiveString cis = new CaseIntensitiveString("Polish");

String s = "polish";

那麼,顯然cis.equals(s)=true。但是問題來了,s.equals(cis) = false。這就違反了對稱性。

解決方案是,如果A類的equals方法中引入了對B類對象的比較,那麼B類反過來也一定要引入對A類的比較。

違反傳遞性:違反這條一般是因為繼承時子類添加了新的值對象。子類添加的資訊會影響equals的比較結果。

比如我們有一個簡單的Point類:

public class Point{    private final int x;    private final int y;    public Point(int x,int y){        this.x = x;        this.y = y;    }    public boolean equals(Object o){        if(!(o instanceof Point))            return false;        Point p = (Point) o;        return this.x == p.x && this.y == p.y;    }}

假設你想擴充這個類,為每個點加一個顏色資訊:

public class ColorPoint extends Point{    private final Color color;    public ColorPoint(int x,int y ,Color c){        super(x,y);        color = c;    }}

equals方法是怎樣呢?有兩種考慮:1.只和有色點比較,要x,y,color都相等才返回true,對於不是有色點的對象,返回結果始終是false
2.有色點也能夠和普通點比較,如果和普通點比較,就比較x,y的值。

看第一種方法的實現:

public boolean equals(Object o){    if(!(o instance of ColorPoint)){        return false;    return super.equalso) && ((ColorPoint) o).color == color;    }}

如果有一個有色點對象cp(1,2,red)和一個普通點對象p(1,2),那麼p.equals(cp) = true,cp.equals(p) = false。違反了對稱性。

第二種方法:

public boolean equals(Object o){    if(!(o instanceof Point))        return false;    if(!(o instanceof ColorPoint))//如果對象不是colorPoint類的話,就用這個對象的equals方法來判斷        return  o.equals(this);    return super.equalso) && ((ColorPoint) o ).color = color;}

這種方法實現了對稱性,但是犧牲了傳遞性。考慮有色點cp1(1,2,red),cp2(1,2,blue)和普通點p(1,2)
有cp1.equals(p) = true ,p.equals(cp2) ,但是cp1.equals(cp2)。違反了傳遞性。

我們無法在擴充可執行個體化的類的同時,既增加新的值組件,又保留equals約定。

怎麼解決呢?

複合優先於繼承。

我們不再繼承Point類,而是建立一個ColorPoint類,在其中加入一個Point類的引用。

今天先寫到這,明天繼續

effective java讀書筆記——對於所有對象都通用的方法

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.