最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

詳解hashCode()和equals()的本質(zhì)區(qū)別和聯(lián)系

 更新時間:2017年09月29日 16:57:37   作者:李社河  
這篇文章主要介紹了詳解hashCode()和equals()的本質(zhì)區(qū)別和聯(lián)系,本文先對兩種方法作了介紹,然后對二者聯(lián)系進(jìn)行分析,具有一定參考價值,需要的朋友可以了解下。

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

equals()方法

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

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

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

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

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

   說明String類中已經(jīng)重寫了equals()方法,如果不重寫equals()方法,那么s1.equals(s2)默認(rèn)比較兩個對象所指向的內(nèi)存地址是否相同,返回值必然為false。

    當(dāng)然接下來我們要改寫equals()方法,必須要遵守通用約定。來自java.lang.Object的規(guī)范,equals方法實(shí)現(xiàn)了等價關(guān)系,以下是要求遵循的5點(diǎn):

1.自反性:對于任意的引用值x,x.equals(x)一定為true。

2.對稱性:對于任意的引用值x 和 y,當(dāng)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比較的對象信息沒有被修改,多次調(diào)用x.equals(y)要么一致地返回true,要么一致地返回false。
5.非空性:對于任意的非空引用值x,x.equals(null)一定返回false。

hashCode()方法

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

public native int hashCode(); 

    hashCode()返回該對象的哈希碼值,該值通常是一個由該對象的內(nèi)部地址轉(zhuǎn)換而來的整數(shù),它的實(shí)現(xiàn)主要是為了提高哈希表(例如java.util.Hashtable提供的哈希表)的性能。

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

     hashCode()的返回值和equals()的關(guān)系如下:

     如果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; 
  } 
} 

詳細(xì)分析

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

1、當(dāng)向集合set中增加對象時,首先計(jì)算要增加對象的hashCode碼,根據(jù)該值來得到一個位置來存放當(dāng)前的對象,當(dāng)在該位置沒有一個對象存在的話,那么集合set認(rèn)為該對象在集合中不存在,直接增加進(jìn)去。如果在該位置有一個對象的話,接著將準(zhǔn)備增加到集合中的對象與該位置上的對象進(jìn)行equals方法比較,如果該equals方法返回false,那么集合認(rèn)為集合中不存在該對象,再進(jìn)行一次散列,將該對象放到散列后計(jì)算出的新地址里,如果equals方法返回true,那么集合認(rèn)為集合中已經(jīng)存在該對象了,不會再將該對象增加到集合中了。

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

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

如果不相等,認(rèn)為兩個對象也不相等,完畢 ; 如果相等,轉(zhuǎn)入2

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

如果不相等,認(rèn)為兩個對象也不相等

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

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

public static void main(String args[]){ 
String s1=new String("zhaoxudong"); //此語句創(chuàng)建了兩個對象,一個是字符串對象“zhaoxudong”(存放于棧中的字面量),另一個是new后在堆中產(chǎn)生的對象。詳細(xì)見下面的四.4 
String s2=new String("zhaoxudong"); 
//上述兩條語句一共是產(chǎn)生了三個對象,因?yàn)闂V兄挥挟a(chǎn)生了一個對象。 
System.out.println(s1==s2);//false 
System.out.println(s1.equals(s2));//true 
System.out.println(s1.hashCode());//s1.hashcode()等于s2.hashcode() ,指向同一內(nèi)存的引用 
System.out.println(s2.hashCode()); //equals和hashCode方法只用于兩個對象的比較和容器中,與對象的創(chuàng)建沒有關(guān)系 
Set hashset=new HashSet(); 
hashset.add(s1); 
hashset.add(s2); /*在添加s1,s2時, hashset認(rèn)為s1和s2是相等的,所以讓s2覆蓋了s1;*/ 
Iterator it=hashset.iterator(); 
      while(it.hasNext()){ 
       System.out.println(it.next()); 
      } //最后在while循環(huán)的時候只打印出了一個”zhaoxudong”。

這是因?yàn)镾tring類已經(jīng)重寫了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; } 
      } 

輸出結(jié)果為:

          1:zhangsan
          1:zhangsan
          3:wangwu
          2:lisi 

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

       這是不是和hashset的原則違背了呢?回答:沒有因?yàn)樵诟鶕?jù)hashcode()對兩次建立newStudent(1,"zhangsan")對象進(jìn)行比較時,生成的是不同的哈希碼值,所以hashset把他當(dāng)作不同的對象對待了,當(dāng)然此時的equals()方法返回的值也不等。那么為什么會生成不同的哈希碼值呢?原因就在于我們自己寫的Student類并沒有重新自己的hashcode()和equals()方法

       所以在比較時,是繼承的object類中的hashcode()方法,它是一個本地方法,比較的是對象的地址(引用地址),使用new方法創(chuàng)建對象,兩次生成的當(dāng)然是不同的對象了,造成的結(jié)果就是兩個對象的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); //&&的優(yōu)先級比==低,所以前面不必加括號 
 
} 
 
public String toString(){return num+":"+name; } 
 
}

根據(jù)重寫的方法,即便兩次調(diào)用了new Student(1,"zhangsan"),我們在獲得對象的哈希碼時,根據(jù)重寫的方法hashcode(),獲得的哈希碼肯定是一樣的。所以運(yùn)行修改后的程序時,我們會看到重復(fù)元素的問題已經(jīng)消除。

總結(jié)

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

相關(guān)文章

  • java+jdbc+mysql+socket搭建局域網(wǎng)聊天室

    java+jdbc+mysql+socket搭建局域網(wǎng)聊天室

    這篇文章主要為大家詳細(xì)介紹了java+jdbc+mysql+socket搭建局域網(wǎng)聊天室,文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2019-01-01
  • Springboot使用thymeleaf動態(tài)模板實(shí)現(xiàn)刷新

    Springboot使用thymeleaf動態(tài)模板實(shí)現(xiàn)刷新

    這篇文章主要介紹了Springboot使用thymeleaf動態(tài)模板實(shí)現(xiàn)刷新,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下
    2020-08-08
  • java仿windows記事本功能完整版

    java仿windows記事本功能完整版

    這篇文章主要為大家詳細(xì)介紹了java仿windows記事本功能完整版,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2019-03-03
  • Java Web請求與響應(yīng)實(shí)例詳解

    Java Web請求與響應(yīng)實(shí)例詳解

    這篇文章主要介紹了Java Web請求與響應(yīng)實(shí)例詳解的相關(guān)資料,需要的朋友可以參考下
    2016-05-05
  • Java數(shù)據(jù)結(jié)構(gòu)與算法之插值查找解析

    Java數(shù)據(jù)結(jié)構(gòu)與算法之插值查找解析

    這篇文章主要介紹了Java數(shù)據(jù)結(jié)構(gòu)與算法之插值查找解析,插值查找算法類似于二分查找,不同的就是插值查找每次從自適應(yīng)mid處開始查找,需要的朋友可以參考下
    2023-12-12
  • Java之HashMap案例詳解

    Java之HashMap案例詳解

    這篇文章主要介紹了Java之HashMap案例詳解,本篇文章通過簡要的案例,講解了該項(xiàng)技術(shù)的了解與使用,以下就是詳細(xì)內(nèi)容,需要的朋友可以參考下
    2021-08-08
  • Java 使用Calendar計(jì)算時間的示例代碼

    Java 使用Calendar計(jì)算時間的示例代碼

    這篇文章主要介紹了Java 使用Calendar計(jì)算時間的示例代碼,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2019-10-10
  • Java編程實(shí)現(xiàn)對象克?。◤?fù)制)代碼詳解

    Java編程實(shí)現(xiàn)對象克?。◤?fù)制)代碼詳解

    這篇文章主要介紹了Java編程實(shí)現(xiàn)對象克?。◤?fù)制)代碼詳解,涉及了克隆的原因,如何實(shí)現(xiàn)克隆,克隆的一般步驟,深克隆與淺克隆的介紹等相關(guān)內(nèi)容,具有一定借鑒價值,需要的朋友可以參考下。
    2017-11-11
  • Mybatis-plus多數(shù)據(jù)源配置的兩種方式總結(jié)

    Mybatis-plus多數(shù)據(jù)源配置的兩種方式總結(jié)

    這篇文章主要為大家詳細(xì)介紹了Mybatis-plus中多數(shù)據(jù)源配置的兩種方式,文中的示例代碼簡潔易懂,感興趣的小伙伴可以跟隨小編一起了解一下
    2022-10-10
  • 阿里巴巴 Sentinel + InfluxDB + Chronograf 實(shí)現(xiàn)監(jiān)控大屏

    阿里巴巴 Sentinel + InfluxDB + Chronograf 實(shí)現(xiàn)監(jiān)控大屏

    這篇文章主要介紹了阿里巴巴 Sentinel + InfluxDB + Chronograf 實(shí)現(xiàn)監(jiān)控大屏,本文通過實(shí)例代碼給大家介紹的非常詳細(xì),具有一定的參考借鑒價值,需要的朋友可以參考下
    2019-09-09

最新評論

昂仁县| 清水河县| 鄂托克旗| 班戈县| 阜城县| 绥棱县| 浦城县| 慈利县| 宾阳县| 孝义市| 轮台县| 杭州市| 牡丹江市| 大埔县| 花莲市| 阿城市| 宝兴县| 恩施市| 霍山县| 迁西县| 静宁县| 玛纳斯县| 灵丘县| 岳西县| 沁源县| 石嘴山市| 阿拉善右旗| 乌拉特后旗| 六枝特区| 大邑县| 临漳县| 定边县| 江阴市| 英超| 昭苏县| 仙游县| 安多县| 博野县| 贵港市| 宁国市| 丰都县|