Java基礎(chǔ) -equals方法

????Object類中的equals方是用來(lái)判斷一個(gè)對(duì)象等于另一個(gè)對(duì)象,至于這個(gè)等于的條件需要自己定義,比如說(shuō),String類的equals相等的條件就是字符串的內(nèi)容必須相同,equals方法返回的值才為true。所以在我們?cè)谧约憾x的類中,equals的重寫是常見(jiàn)的!這里主要展示equals的特性和equals的正確寫法,至于equals方法具體的含義這里不介紹!

1. 舉一個(gè)例子

????在這介紹其他的,我們先來(lái)看看正確的寫法

public class Animal {
    private String name = null;

    public Animal(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(this == obj) {
            return true;
        }
        if(obj == null) {
            return false;
        }
        if(this.getClass() != obj.getClass()) {
            return false;
        }
        Animal animal = (Animal) obj;
        //return this.name.equals(animal.name);
        //這個(gè)方法只在JDK7及其以后才有的
        //這個(gè)方法能夠保證兩個(gè)name其中只有一個(gè)為null的話,返回的false
        //如果兩個(gè)都為null的話,返回的是true
        //如果兩個(gè)都不為null的話,具體看情況
        return Objects.equals(this.name, animal.name);
    }
}

????從上面的代碼中我們看到是,Animal類的equals方法判斷的相等條件是name是否為相同。說(shuō)實(shí)話,判斷的條件非常的簡(jiǎn)單,但是我們的代碼寫的非常復(fù)雜??赡苡腥藭?huì)這樣寫的:

    public boolean equals(Object obj) {
        if(! (obj instanceof Animal)) {
            return false;
        }
        Animal animal = (Animal) obj;
        return this.name.equals(animal.name);
    }

????實(shí)際上,上面的代碼是有很大的問(wèn)題,至于有什么問(wèn)題,待會(huì)再說(shuō)!這里我們來(lái)解釋一下正確equals方法寫的代碼:

1. this == obj, 毫無(wú)疑問(wèn),如果兩個(gè)對(duì)象的內(nèi)存都是相同的話,那么肯定是同一個(gè)對(duì)象了。
2. this == null, 同樣的話,如果傳進(jìn)來(lái)的對(duì)象是null的話,肯定為false。
3. this.getClass == obj.getClass, 這個(gè)條件可能讓人有點(diǎn)疑惑。我來(lái)解釋一下,getClass是獲得當(dāng)前的對(duì)象的Class對(duì)象,至于什么是Class對(duì)象,這里不解釋,需要的記得是:同一類的所有對(duì)象的獲得的Class對(duì)象都是同一個(gè)Class對(duì)象,也就是說(shuō),如果這里的this與obj不屬于同一個(gè)類的,那么肯定為false。

????那么這種寫法有好處呢,等我把列出另一個(gè)類的代碼再說(shuō)吧!

public class Dog extends Animal{
    private int age = 0;
    public Dog(String name, int age) {
        super(name);
        this.age = age;
    }
    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }
    
    @Override
    public boolean equals(Object obj) {
        if(!super.equals(obj)) {
            return false;
        }
        Dog dog = (Dog) obj;
        return this.age == dog.age;
    }
}

????我們發(fā)現(xiàn)Dog類繼承于Animal類,并且重寫了父類的equals方法。在Dog類中equals方法,我們先來(lái)判斷了這兩個(gè)對(duì)象是否是相等的,其次再比較了age是否相同的。其中先調(diào)用了父類的equals來(lái)判斷,再來(lái)判斷子類本身的條件,這種方法有幾個(gè)好處:

1. 符合繼承的特性,當(dāng)且僅當(dāng)他們通過(guò)父類equals才有可能判斷子類的條件,因?yàn)槿绻慌袛喔割惖膃quals的話,當(dāng)父類的equals返回的是false,但是通過(guò)調(diào)用子類的equals卻返回true。這個(gè)根本不符合面向?qū)ο蟮奶匦?,?shí)際點(diǎn),如果兩個(gè)兒子老爸都不相同的話,兒子怎么可能相同!
2. 避免了obj是Dog類的子類(雖然這里Dog類沒(méi)有子類)。因?yàn)檫@里,我們先來(lái)調(diào)用父類的equals,父類的equals方法中:this.getClass() == obj.getClass 會(huì)幫助我們判斷這兩個(gè)類是否是同一個(gè)類。按照我們以往的寫法,使用instanceof關(guān)鍵字來(lái)進(jìn)行判斷的是有很大的問(wèn)題的,如果this是Dog類的對(duì)象,但是obj的實(shí)際類型是Dog子類的對(duì)象,如果使用 obj instanceof Dog 這個(gè)返回的肯定為true,如果通過(guò)了我們這個(gè)判斷語(yǔ)句,最后來(lái)判斷我們的age。實(shí)際上,這兩個(gè)對(duì)象肯定不是同一個(gè)對(duì)象,所以最后用age來(lái)判斷是有問(wèn)題的。至于這個(gè)問(wèn)題的詳細(xì)解釋,待會(huì)還會(huì)提及!

2. equals方法的特性

????上面留了一些伏筆,這里將詳細(xì)的解釋,但是在解釋之前,我們先來(lái)看看equals方法的特性:

1. 自反性:對(duì)于任何的非空對(duì)象,x.equals(x)返回肯定為true。

2. 對(duì)稱性:對(duì)于任何兩個(gè)非空對(duì)象x、y,如果x.equals(y)返回的是true,那么y.equals(x)返回的是肯定也為true。

3. 傳遞性:對(duì)于任何三個(gè)非空對(duì)象x、y、z,如果x.equals(y)為true,并且y.equals(z),那么x.equals(z)肯定也為true。

4. 一致性:如果對(duì)象x和對(duì)象y沒(méi)有發(fā)生任何變換的話,反復(fù)調(diào)用y.equals(x)應(yīng)該返回的是一樣的結(jié)果。

5. 對(duì)于任意非空對(duì)象x,x.equals(null)應(yīng)該返回的是false。

????針對(duì)這些特性,我們拿一個(gè)特性來(lái)解釋為什么使用instanceof關(guān)鍵字來(lái)進(jìn)行判斷有很大的問(wèn)題。
????假設(shè),記住這里是假設(shè):如果Animal類的equals方法和Dog類的equals方法使用的是instanceof關(guān)鍵字來(lái)判斷的,也就是下面的代碼:

Animal類的equals方法:
    @Override
    public boolean equals(Object obj) {
        if(!(obj instanceof Animal)) {
            return false;
        }
        Animal animal = (Animal) obj;
        return Objects.equals(this.name, animal.name);
    }
Dog類的equals方法:
    @Override
    public boolean equals(Object obj) {
        if (!(obj instanceof Dog)) {
            return false;
        }
        Dog dog = (Dog) obj;
        return this.age == dog.age;
    }
然后我們?cè)趍ain方法里面這么寫:
    public static void main(String[] args) {
        Animal a1 = new Animal("pby");
        Dog d1 = new Dog("pby", 21);
        System.out.println(a1.equals(d1));
        System.out.println(d1.equals(a1));
    }

????我們可以看到的是第一個(gè)結(jié)果返回的true,但是第二個(gè)返回的false。這個(gè)就有問(wèn)題了,不符合equals方法的對(duì)稱性。
????我們來(lái)分析一下,當(dāng)a1.equals(d1)時(shí),調(diào)用的Animal類中的equals方法,這個(gè)方法對(duì)name進(jìn)行判斷,首先d1 instanceof Animal 肯定為true,因?yàn)镈og類是Animal的子類,所以if條件沒(méi)有屏蔽掉d1,由于兩個(gè)對(duì)象的name是相同的,所以返回值是true,但是真正的結(jié)果是false,因?yàn)樗麄儾粚儆谕粋€(gè)類!至于第二個(gè)為什么是false,這里將不在解釋了!
????然后我們回來(lái)看正確寫法,this.getClass == obj.getClass這個(gè)判斷就能夠?qū)⑽覀兊膁1屏蔽掉!

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 1.import static是Java 5增加的功能,就是將Import類中的靜態(tài)方法,可以作為本類的靜態(tài)方法來(lái)...
    XLsn0w閱讀 1,428評(píng)論 0 2
  • 面向?qū)ο笾饕槍?duì)面向過(guò)程。 面向過(guò)程的基本單元是函數(shù)。 什么是對(duì)象:EVERYTHING IS OBJECT(萬(wàn)物...
    sinpi閱讀 1,220評(píng)論 0 4
  • 1. Java基礎(chǔ)部分 基礎(chǔ)部分的順序:基本語(yǔ)法,類相關(guān)的語(yǔ)法,內(nèi)部類的語(yǔ)法,繼承相關(guān)的語(yǔ)法,異常的語(yǔ)法,線程的語(yǔ)...
    子非魚_t_閱讀 34,741評(píng)論 18 399
  • 一:java概述:1,JDK:Java Development Kit,java的開(kāi)發(fā)和運(yùn)行環(huán)境,java的開(kāi)發(fā)工...
    ZaneInTheSun閱讀 2,815評(píng)論 0 11
  • 從三月份找實(shí)習(xí)到現(xiàn)在,面了一些公司,掛了不少,但最終還是拿到小米、百度、阿里、京東、新浪、CVTE、樂(lè)視家的研發(fā)崗...
    時(shí)芥藍(lán)閱讀 42,818評(píng)論 11 349

友情鏈接更多精彩內(nèi)容