Java學習從菜鳥變大鳥之一 hashCode()和equals()的本質區別和聯絡

來源:互聯網
上載者:User

在學習java,根據視頻做執行個體的過程中,對equals和hashcode兩個方法理解稍微深刻一點,主要是它們兩個很容易混淆,容易出錯,自己又通過網上的資料學習,和大家分享

equals()方法


equals是Object類提供的方法之一,眾所周知,每一個java類都繼承自Object類,

所以說每一個對象都有equals這個方法。而我們在用這個方法時卻一般都重寫這個方法,why?



先看一個Object類中equals()方法的原始碼:

 

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

 

    從這個方法中可以看出,只有當一個執行個體等於它本身的時候,equals()才會返回true值。通俗地說,此時比較的是兩個引用是否指向記憶體中的同一個對象,也可以稱做是否執行個體相等。而我們在使用equals()來比較兩個指向值對象的引用的時候,往往希望知道它們邏輯上是否相等,而不是它們是否指向同一個對象——這就是我們通常重寫這個方法的原因。


Strings1 = new String(“kvill”),String s2 = new String(“kvill”);s1.equals(s2)為ture,


       說明String類中已經重寫了equals()方法,如果不重寫equals()方法,那麼s1.equals(s2)預設比較兩個對象所指向的記憶體位址是否相同,返回值必然為false。


    當然接下來我們要改寫equals()方法,必須要遵守通用約定。來自java.lang.Object的規範,equals方法實現了等價關係,以下是要求遵循的5點:


1.自反性:對於任意的引用值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,如果用於equals比較的對象資訊沒有被修改,多次調用x.equals(y)要麼一致地返回true,要麼一致地返回false。

5.非空性:對於任意的非Null 參考值x,x.equals(null)一定返回false。


hashCode()方法


hashcode()這個方法也是從object類中繼承過來的,在object類中定義如下:

public native int hashCode(); 

    hashCode()返回該對象的雜湊碼值,該值通常是一個由該對象的內部地址轉換而來的整數,它的實現主要是為了提高雜湊表(例如java.util.Hashtable提供的雜湊表)的效能。


    必須銘記:在每個重寫了equals方法的類中,你必須也要重寫hashCode方法。如果不這樣做的話,就會違反Object.hashCode的通用約定,從而導致該類無法與所有基於散列值(hash)的集合類結合在一起正常運行。 

     hashCode()的返回值和equals()的關係如下:

     如果x.equals(y)返回“true”,那麼x和y的hashCode()必須相等。 

     如果x.equals(y)返回“false”,那麼x和y的hashCode()有可能相等,也有可能不等。


public class TestEquals {public static void main(String args[]) {Student s1 = new Student("張一", 6);Student s2 = new Student("張一", 6);if (s1.equals(s2)) {System.out.println("相同  s1的代碼:" + s1.hashCode() + "  s2的代碼:"+ s2.hashCode());} else {System.out.println("不相同");}}}class Student {private int age;private String name;public Student() {}public Student(String name, int age) {this.age = age;this.name = name;}public int getAge() {return age;}public void setAge(int age) {this.age = age;}public String getName() {return name;}public void setName(String name) {this.name = name;}public int hashCode() {return (this.name.hashCode() + this.age) * 31;}public boolean equals(Object obj) {boolean result = false;if (obj == null) {result = false;}if (this == obj) {result = true;}if (obj instanceof Student) {Student stu = (Student) obj;if (stu.getName().equals(this.name) && stu.getAge() == (this.age)) {result = true;}} else {result = false;}return result;}}

詳細分析


equals()是判讀兩個Set是否相等[前提是equals()在類中被覆蓋]。==決定引用值是否指向同一對象。


      1、當向集合set中增加對象時,首先計算要增加對象的hashCode碼,根據該值來得到一個位置來存放當前的對象,當在該位置沒有一個對象存在的話,那麼集合set認為該對象在集合中不存在,直接增加進去。如果在該位置有一個對象的話,接著將準備增加到集合中的對象與該位置上的對象進行equals方法比較,如果該equals方法返回false,那麼集合認為集合中不存在該對象,再進行一次散列,將該對象放到散列後計算出的新地址裡,如果equals方法返回true,那麼集合認為集合中已經存在該對象了,不會再將該對象增加到集合中了。


      2、當重寫equals方法時,必須要重寫hashCode方法。在java的集合中,判斷兩個對象是否相等的規則是:

            1),判斷兩個對象的hashCode是否相等

              如果不相等,認為兩個對象也不相等,完畢 ; 如果相等,轉入2

            2),判斷兩個對象用equals運算是否相等

            如果不相等,認為兩個對象也不相等

            如果相等,認為兩個對象相等(equals()是判斷兩個對象是否相等的關鍵)

            可見hashcode()相等時,equals()方法也可能不等。



public static void main(String args[]){String s1=new String("zhaoxudong"); //此語句建立了兩個對象,一個是字串對象“zhaoxudong”(存放於棧中的字面量),另一個是new後在堆中產生的對象。詳細見下面的四.4String s2=new String("zhaoxudong");//上述兩條語句一共是產生了三個對象,因為棧中只有產生了一個對象。System.out.println(s1==s2);//falseSystem.out.println(s1.equals(s2));//trueSystem.out.println(s1.hashCode());//s1.hashcode()等於s2.hashcode() ,指向同一記憶體的引用System.out.println(s2.hashCode()); //equals和hashCode方法只用於兩個對象的比較和容器中,與對象的建立沒有關係Set hashset=new HashSet();hashset.add(s1);hashset.add(s2); /*在添加s1,s2時, hashset認為s1和s2是相等的,所以讓s2覆蓋了s1;*/Iterator it=hashset.iterator();            while(it.hasNext()){             System.out.println(it.next());            } //最後在while迴圈的時候只列印出了一個”zhaoxudong”。 



這是因為String類已經重寫了equals()方法和hashcode()方法。


但是看下面的程式:

public class HashSetTest {   public static void main(String[] args)   {                 HashSet hs=new HashSet();                 hs.add(new Student(1,"zhangsan"));                 hs.add(new Student(2,"lisi"));                 hs.add(new Student(3,"wangwu"));                 hs.add(new Student(1,"zhangsan"));                 Iterator it=hs.iterator();                 while(it.hasNext()){                        System.out.println(it.next());                 } } }class Student {     int num;     String name;     Student(int num,String name) {                this.num=num;                 this.name=name; }     public String toString() { return num+":"+name; }           }      

輸出結果為:

                   1:zhangsan

                   1:zhangsan

                   3:wangwu

                   2:lisi



為什麼hashset添加了相等的元素呢?


       這是不是和hashset的原則違背了呢?回答:沒有因為在根據hashcode()對兩次建立newStudent(1,"zhangsan")對象進行比較時,產生的是不同的雜湊碼值,所以hashset把他當作不同的對象對待了,當然此時的equals()方法返回的值也不等。那麼為什麼會產生不同的雜湊碼值呢?原因就在於我們自己寫的Student類並沒有重新自己的hashcode()和equals()方法

       所以在比較時,是繼承的object類中的hashcode()方法,它是一個本地方法,比較的是對象的地址(引用地址),使用new方法建立對象,兩次產生的當然是不同的對象了,造成的結果就是兩個對象的hashcode()返回的值不一樣。那麼怎麼解決這個問題呢?


原因是:在Student類中重新hashcode()和equals()方法。


例如:class Student{int num;String name;Student(int num,String name){            this.num=num;            this.name=name; }public int hashCode(){ //重寫hashCode的方法            return num*name.hashCode(); }public boolean equals(Object o) {            Student s=(Student)o;            return num==s.num && name.equals(s.name); //&&的優先順序比==低,所以前面不必加括弧}public String toString(){return num+":"+name; }} 

      根據重寫的方法,即便兩次調用了new Student(1,"zhangsan"),我們在獲得對象的雜湊碼時,根據重寫的方法hashcode(),獲得的雜湊碼肯定是一樣的。所以運行修改後的程式時,我們會看到重複元素的問題已經消除。

總結

這塊知識比較容易出錯,理解一定要深刻,多多的實踐會對原理與定義理解的更加的深刻,To Do,To Do……,祝各位朋友,新年快樂哈!



相關文章

聯繫我們

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