equals與hashCode

關(guān)于“==”操作符

眾所周知,在Java中對于基本數(shù)據(jù)類型來說“==”操作符用于比較兩個變量的值是否相等,而對于引用類型來說“==”比較的是對象指向的引用是否一致。舉個例子,先定義一個User類:

public class User{
          private String name;
          private int age;

          public User(String name,int age){
                this.name = name;
                this.age = age;
          }

          public void setName(String name){
              this.name = name;
          }

          public String getName(){
               return name;
          }
}

在測試類的main函數(shù)中添加如下代碼可以得到輸出:

User user1 = new User("abc",12);
User user2 = new User("abc",12);
User user3 = user1;
System.out.println(user1==user2);//輸出false,user1和user2指向兩個不同的引用
System.out.println(user1==user3);//輸出true,user1的引用被傳遞給了user3
user3.setName("cde");//改變user3中的值
System.out.println(user1.getName());//輸出“cde”,user1與user3指向同一引用
System.out.println(user1 == user3);//輸出true,由于user1與user3兩個對象具有相同的引用,改變user3其實就是改變user1。

由此可得:當用“=”把一個引用對象賦值給另外一個引用對象后,此時使用“==”比較兩個對象返回true,兩個對象操作的是同一個引用,修改一個對象會影響另外一個對象。

關(guān)于equals方法

equals方法存在于Object類中,所以Java所有類默認都有這個方法,下面看看Object中equals方法是怎么實現(xiàn)的

public boolean equals(Object obj) {
    return (this == obj);
}

從上面的代碼可以看出在Object中的equals方法是使用“==”符號比較兩個對象是否相同,所以把上一節(jié)代碼中的“==”換成equals后結(jié)果是一樣的。此時有人可能會有疑問,那為啥平時使用的String類型只要字符串一樣equals方法就返回true,那是因為String類重寫了equals方法。我們也可以重寫User類的equals方法代碼如下:

public boolean equals(Object obj){
    if(this == obj){
      return true;
    }
    if(obj instanceof User){
        User user = (User)obj;
        if(this.name.equals(user.getName)&&this.age == user.getAge()){
            return true;
        }
    }
    return false;
}

main函數(shù)與輸出代碼如下:

User user1 = new User("abc",12);
User user2 = new User("abc",12);
User user3 = new User("cde",12);
System.out.println(user1.equals(user2));//輸出true,name和age都相等
System.out.println(user1.equals(user3));//輸出false,name不等。

從結(jié)果來看實現(xiàn)了我們想要的,但是這里面還存在一個問題,因為這個類在重寫了equals方法的同時卻沒有重寫hashCode方法,這會導(dǎo)致這個類無法與所有基于散列的集合類一起正常使用。讓我們看下面這個例子:

Map<User,String> map = new HashMap<>();
map.put(new User("xiaojian",12),"abc");
System.out.println(map.get(new User("xiaojian",12)));//輸出null,并沒有輸出我們期望的結(jié)果“abc”

上面的結(jié)果是因為上面put與get的實例雖然相等,但是他們的hashCode卻不相等,HashMap在查詢時當檢測到hashCode不一致時也不會檢驗對象的一致性。為了保證HashMap能正常工作,我們重寫User類的hashCode方法如下:

public int hashCode(){
    return 17;
}

這個時候上面那段代碼輸出“abc”,得到我們期望的結(jié)果了,但這時別高興太早,由于這里返回的固定值,所有User對象都具有一個相同的hashCode,這違反了hashCode的三大原則:

image.png

那么要怎么改呢?下面是修改的一些原則:

image.png

根據(jù)這個原則修改hashCode方法如下:

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

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

  • 1. Java基礎(chǔ)部分 基礎(chǔ)部分的順序:基本語法,類相關(guān)的語法,內(nèi)部類的語法,繼承相關(guān)的語法,異常的語法,線程的語...
    子非魚_t_閱讀 34,734評論 18 399
  • 問:兩個對象值相同 (tmp1.equals(tmp2) == true) 但卻可有不同的 HashCode 值,...
    Little丶Jerry閱讀 254評論 0 3
  • 摘要 equals描述的是一種等價關(guān)系,不僅僅是引用相等 equals重載需要滿足自反性、對稱性與傳遞性 任何實例...
    周兔子閱讀 2,076評論 4 3
  • 從三月份找實習(xí)到現(xiàn)在,面了一些公司,掛了不少,但最終還是拿到小米、百度、阿里、京東、新浪、CVTE、樂視家的研發(fā)崗...
    時芥藍閱讀 42,816評論 11 349
  • 有些破碎,只是為了愈合(四首) ⊙江山 我有一片江山無人交付—— 有風(fēng)風(fēng)塵仆仆 有草熙熙攘攘 有鳥飛過,失落幾聲鳥...
    劉永軍的小房子閱讀 182評論 0 4

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