java重寫equals方法需要注意的幾點

來源:互聯網
上載者:User

標籤:

為什麼equals()方法要重寫?

判斷兩個對象在邏輯上是否相等,如根據類的成員變數來判斷兩個類的執行個體是否相等,而繼承Object中的equals方法只能判斷兩個引用變數是否是同一個對象。這樣我們往往需要重寫equals()方法。

我們向一個沒有重複對象的集合中添加元素時,集合中存放的往往是對象,我們需要先判斷集合中是否存在已知對象,這樣就必須重寫equals方法。

怎樣重寫equals()方法?

重寫equals方法的要求:
1、自反性:對於任何非Null 參考x,x.equals(x)應該返回true。
2、對稱性:對於任何引用x和y,如果x.equals(y)返回true,那麼y.equals(x)也應該返回true。
3、傳遞性:對於任何引用x、y和z,如果x.equals(y)返回true,y.equals(z)返回true,那麼x.equals(z)也應該返回true。
4、一致性:如果x和y引用的對象沒有發生變化,那麼反覆調用x.equals(y)應該返回同樣的結果。
5、非空性:對於任意非Null 參考x,x.equals(null)應該返回false。

 

1、自反性原則

    在JavaBean中,經常會覆寫equals方法,從而根據實際業務情況來判斷兩個對象是否相等,比如我們寫一個person類,根據姓名來判斷兩個person類執行個體對象是否相等。代碼如下:

public class Person {    private String name;     public Person(String name){        this.name = name;    }     public String getName() {        return name;    }     public void setName(String name) {        this.name = name;    }     @Override    public boolean equals(Object obj) {        if (obj instanceof Person) {            Person person= (Person) obj;            return name.equalsIgnoreCase(person.getName().trim());        }        return false;    }    public static void main(String[] args){        Person p1=new Person("張三");        Person p2=new Person("張三    ");        List<Person> list = new ArrayList<Person>();        list.add(p1);        list.add(p2);        System.out.println("是否包含張三:"+list.contains(p1));        System.out.println("是否包含張三:"+list.contains(p2));    }}

    list中含有這個產生的person對象,結果應該為true,但是實際結果:    這裡考慮了字串空格的問題,去除前後的空格。

    是否包含張三:true

    是否包含張三:false

    第二個為什麼會是false呢?原因在於list中檢查是否含有元素時是通過調用對象的equals方法來判斷的,也就是說 contains(p2)傳遞進去會依次執行p2.equals(p1)、p2.equals(p2),只要一個返回true,結果就是true。但是這裡p2.equals(p2)返回的是false?由於我們對字元前後進行了空格的切割造成p2.equals(p2)的比較實際上是:“張三   ”.equals(“張三”),一個有空格,一個沒有空格就出錯了。

    這個違背了equals的自反性原則:對於任何非Null 參考x,x.equals(x)應該返回true。

    這裡只要去掉trim方法就可以解決。

2、對稱性原則

    上面這個例子,還並不是很好,如果我們傳入null值,會怎麼樣呢?增加一條語句:Person p2=new Person(null);

結果:

12 是否包含張三:trueException in thread "main" java.lang.NullPointerException

原因在執行p2.equals(p1)時,由於p2的name是一個null值,所以調用name.equalsIgnoreCase()方法時就會報null 指標異常。

這是在覆寫equals方法時沒有遵循對稱性原則:對於任何應用x,y的情形,如果想x.equals(y)返回true,那麼y.equals(x),也應該返回true。

應該在equals方法裡加上是否為null值的判斷:

@Override    public boolean equals(Object obj) {        if (obj instanceof Person) {            Person person= (Person) obj;            if (person.getName() == null || name == null) {                return false;            }else{                return name.equalsIgnoreCase(person.getName());            }        }        return false;    }

3、傳遞性原則  

現在我們有一個Employee類繼承自person類:

public class Employee extends Person{    private int id;      public int getId() {        return id;    }    public void setId(int id) {        this.id = id;    }    public Employee(String name,int id) {        super(name);        this.id = id;        // TODO Auto-generated constructor stub    }    @Override    public boolean equals(Object obj) {        if(obj instanceof Employee){            Employee e = (Employee)obj;            return super.equals(obj) && e.getId() == id;        }        return super.equals(obj);    }     public static void main(String[] args){        Employee e1=new Employee("張三",12);        Employee e2=new Employee("張三",123);        Person p1 = new Person("張三");         System.out.println(p1.equals(e1));        System.out.println(p1.equals(e2));        System.out.println(e1.equals(e2));    }}

  只有在name和ID都相同的情況下才是同一個員工,避免同名同姓的。在main裡定義了,兩個員工和一個社會閑雜人員,雖然同名同姓但肯定不是同一個人。運行結果應該三個都是false才對。但是:

true

true

false

    p1盡然等於e1,也等於e2,不是同一個類的執行個體也相等了?因為p1.equals(e1)是調用父類的equals方法進行判斷的它使用instanceof關鍵字檢查e1是否是person的執行個體,由於employee和person是繼承關係,結果就是true了。但是放過來就不成立,e1,e2就不等於p1,這也是違反對稱性原則的一個典型案例。

   e1竟然不等於e2?e1.equals(e2)調用的是Employee的equals方法,不僅要判斷姓名相同還有判斷工號相同,兩者的工號不同,不相等時對的。但是p1等於e1,也等於e2,e1卻不等於e2,這裡就存在矛盾,等式不傳遞是因為違反了equals的傳遞性原則:對於執行個體對象x、y、z;如果x.equals(y)返回true,y.equals(z)返回true,那麼x.equals(z)也應該返回true。

    上述情況會發生是因為父類使用instanceof關鍵字(是否是這個特定類或者是它的子類的一個執行個體),用來判斷是否是一個類的執行個體對象的,這很容易讓子類“鑽空子”。想要解決也很簡單,使用getClass進行類型的判斷,person類的equals方法修改如下:

@Override    public boolean equals(Object obj) {        if (obj != null && obj.getClass() == this.getClass()) {            Person person= (Person) obj;            if (person.getName() == null || name == null) {                return false;            }else{                return name.equalsIgnoreCase(person.getName());            }        }        return false;    }


4、必須覆寫hashCode方法這樣結果就是三個false。

覆寫equals方法就必須覆寫hashCode方法,這是Javaer都知道的。原因就是HashMap的底層處理機制是以數組的方式儲存map條目的,這其中的關鍵是這個數組下標的處理機制:依據傳入元素的hashCode方法的傳回值決定其數組的下標,如果該數組位置上已經有了map條目,且與傳入的索引值相等則不處理,若不相等則覆蓋;如果數組位置沒有條目,則插入,並加入到map條目的鏈表中。同理檢查鍵是否存在也是根據雜湊嗎確定文職,然後遍曆尋找索引值的。

那麼對象的hashCode方法返回的是什麼呢?他是一個對象的雜湊碼,是有Object類的本地方法產生的,確保每個對象有一個雜湊碼。

具體的可以看另一篇博文:http://www.cnblogs.com/silence-hust/p/4510574.html

?

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

java重寫equals方法需要注意的幾點

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在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.