一区二区三区在线-一区二区三区亚洲视频-一区二区三区亚洲-一区二区三区午夜-一区二区三区四区在线视频-一区二区三区四区在线免费观看

服務器之家:專注于服務器技術及軟件下載分享
分類導航

PHP教程|ASP.NET教程|Java教程|ASP教程|編程技術|正則表達式|C/C++|IOS|C#|Swift|Android|VB|R語言|JavaScript|易語言|vb.net|

服務器之家 - 編程語言 - Java教程 - 詳解hashCode()和equals()的本質區別和聯系

詳解hashCode()和equals()的本質區別和聯系

2021-01-13 14:31李社河 Java教程

這篇文章主要介紹了詳解hashCode()和equals()的本質區別和聯系,本文先對兩種方法作了介紹,然后對二者聯系進行分析,具有一定參考價值,需要的朋友可以了解下。

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

equals()方法

equals是Object類提供的方法之一,眾所周知,每一個java類都繼承自Object類,所以說每一個對象都有equals這個方法。而我們在用這個方法時卻一般都重寫這個方法,why?

先看一個Object類中equals()方法的源代碼:

?
1
2
3
public boolean equals(Object obj) { 
  return (this == obj); 
}

 

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

?
1
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.非空性:對于任意的非空引用值x,x.equals(null)一定返回false。

hashCode()方法

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

?
1
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()有可能相等,也有可能不等。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
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()方法也可能不等。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public static void main(String args[]){
String s1=new String("zhaoxudong"); //此語句創建了兩個對象,一個是字符串對象“zhaoxudong”(存放于棧中的字面量),另一個是new后在堆中產生的對象。詳細見下面的四.4
String s2=new String("zhaoxudong");
//上述兩條語句一共是產生了三個對象,因為棧中只有產生了一個對象。
System.out.println(s1==s2);//false
System.out.println(s1.equals(s2));//true
System.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()方法。

但是看下面的程序:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
>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
2
3
4
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()方法。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
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(),獲得的哈希碼肯定是一樣的。所以運行修改后的程序時,我們會看到重復元素的問題已經消除。

總結

這塊知識比較容易出錯,理解一定要深刻,多多的實踐會對原理與定義理解的更加的深刻。有什么問題可以隨時留言,小編會及時回復大家的。感謝大家對本站的支持。

原文鏈接:http://blog.csdn.net/lishehe/article/details/18839495

延伸 · 閱讀

精彩推薦
主站蜘蛛池模板: 久热在线这里只有精品7 | 精品无码久久久久久久久 | 成人a级特黄毛片 | 亚洲瑟瑟网 | 秋葵视频成人 | 亚洲sss综合天堂久久久 | 日本黄a | 亚洲欧美综合一区 | 免费在线观看伦理片 | 成人欧美一区二区三区 | 热巴在公交车h文 | 亚洲国产福利精品一区二区 | 情趣内衣在线观看 | 日韩视频免费一区二区三区 | 国产高清视频一区二区 | 亚洲欧美色综合图小说 | 美女在尿口隐私视频 | 久久天天综合 | 日本搜子同屋的日子2国语 日本爽p大片免费观看 | 电车痴汉(han)| 国产一级持黄大片99久久 | 久草青青在线 | 全色黄大色黄大片爽一次 | 高清国语自产拍免费视频国产 | 插插好爽爽爽 | 亚洲国产综合久久精品 | 国产亚洲欧美一区二区三区 | 国产精品香蕉一区二区三区 | aⅴ视频在线免播放观看 | 美女禁18 | www免费视频com | 三年片韩国在线观看 | 波多野结衣一区免费作品 | 息与子中文字幕完整在线 | 国产成人精品一区二区仙踪林 | 男女姓交大视频免费观看 | 亚洲精品免费在线观看 | 亚洲高清中文字幕精品不卡 | 日本xxwwwxxxx| 亚洲日本va中文字幕 | 亚洲精品一区二区三区中文字幕 |