日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > java >内容正文

java

【Java】浅析equals()和hashCode()

發布時間:2025/3/15 java 13 豆豆
生活随笔 收集整理的這篇文章主要介紹了 【Java】浅析equals()和hashCode() 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

總覽equals( ) 方法

  • 理解equals()方法和==運算符的區別是非常重要的。

    • 默認情況下(即沒有被重寫時)equals()只能比較引用類型,"=="既能 比較引用類型又能比較基本類型。
    • equals()方法從Object類繼承,即比較對象引用的值
    • 一般都被子類方法覆蓋,不再比較引用的值
  • "=="運算符:

    • 比較基本數據類型:相當于算術等號。
    • 比較引用數據類型:比較引用的值,不能被覆蓋。
  • 通常情況,子類要重寫equals( ),改變它的含義。所以有的類中 equals( )是比較地址,有的類中該方法就不比較地址,具體的,就看子類新定義的該方法的規定。建議看看包裝類中的equals()方法,蠻有趣的。

  • 在Java中有個規定:如果equals( )返回兩個對象是相等的,那這兩個對象上調用hashCode( )返回的整數必須相等。否則在使用Hash類型集合時就會產生錯誤。

  • 注意:覆蓋equals( )方法同時,還要記得覆蓋hashCode( )方法。 需要說明,如果equals( )返回兩個對象不等,它們的hashCode( )也 可以返回相同的整數。但是最好讓它們的hashCode( )返回不同的整 數,這有利于提高Hash類型集合的性能。

  • 重寫equals方法時,一定要重寫hashcode()方法嗎?

    • hashcode的調用的條件:

      • 想往map里面放一個類作為map的鍵值,這個類又是自己設計的;
      • 雖然類不是自己寫的,但是你修改了這個類的equals方法;
    • 如果滿足上述調用條件,就要注意重寫hashcode方法。
      這樣 當你往map 里放值得時候,系統會調用這個對象的.hashcode()方法來生成相應的 hash值,來映射相應的對象。

  • 如果同一個類的兩個對象的屬性值相等,那么他們的hashcode一定相等嗎?這個要看你具體如何實現你的hashcode,如果你希望他們的值一樣hashcode也一樣,你就可以這樣實現。 但是hashcode的實現,一般要滿足幾個特征,比如自反性、對稱性、傳遞性那些。

等價關系與equals( )

離散數學的知識:

設R是A上關系,若R是自反的、對稱的和傳遞的,則稱R是A中的等價關系。
若a,b∈A,且aRb,則稱a與b等價若 a,b\in A,且aRb,則稱a與b等價a,bAaRbab

equals() 其實就是一種等價關系,它指定了某種方法(默認的hashCode()、重寫的hashCode()、自定義的equals()判據等)來判定這種等價關系。

我們自己想要重寫equals(),為了保證這種等價關系,就需要維護自反性、對稱性、傳遞性。

其實,簡單的測試還不太夠,最好是有形式化的證明。

這篇文章中就涉及了equals()的自反性、對稱性、傳遞性,做了簡單的測試……
其實我也很無奈,這是我在準備大學里一門核心專業課考試的前一晚總結的,內心真正比較喜歡的文章,but沒人看,Readers更喜歡比較浮夸的文章

IDE自動生成equals( )和hashCode( )

如果你確實懶得重寫equals()和hashCode(),IDE支持自動生成這兩個方法。

首先,Person類已經完成到了這個程度:

import java.io.Serializable;public class Person implements Serializable {private static final long serialVersionUID = 1L;private Integer id;private String name;private Integer age;public Person(Integer id, String name, Integer age) {this.id = id;this.name = name;this.age = age;}public Integer getId() {return id;}public void setId(Integer id) {this.id = id;}public String getName() {return name;}public void setName(String name) {this.name = name;}public Integer getAge() {return age;}public void setAge(Integer age) {this.age = age;}@Overridepublic String toString() {return "Person{" + "id=" + id + ", name='" + name + '\'' + ", age=" + age + '}';}}

Eclipse


import java.io.Serializable; import java.util.Objects;public class Person implements Serializable {private static final long serialVersionUID = 1L;private Integer id;private String name;private Integer age;public Person(Integer id, String name, Integer age) {this.id = id;this.name = name;this.age = age;}public Integer getId() {return id;}public void setId(Integer id) {this.id = id;}public String getName() {return name;}public void setName(String name) {this.name = name;}public Integer getAge() {return age;}public void setAge(Integer age) {this.age = age;}@Overridepublic String toString() {return "Person{" + "id=" + id + ", name='" + name + '\'' + ", age=" + age + '}';}@Overridepublic int hashCode() {return Objects.hash(id, name);}@Overridepublic boolean equals(Object obj) {if (this == obj) {return true;}if (obj == null) {return false;}if (!(obj instanceof Person)) {return false;}Person other = (Person) obj;return Objects.equals(id, other.id) && Objects.equals(name, other.name);}}

IntelliJ IDEA






import java.io.Serializable; import java.util.Objects;public class Person implements Serializable {private static final long serialVersionUID = 1L;private Integer id;private String name;private Integer age;public Person(Integer id, String name, Integer age) {this.id = id;this.name = name;this.age = age;}public Integer getId() {return id;}public void setId(Integer id) {this.id = id;}public String getName() {return name;}public void setName(String name) {this.name = name;}public Integer getAge() {return age;}public void setAge(Integer age) {this.age = age;}@Overridepublic String toString() {return "Person{" + "id=" + id + ", name='" + name + '\'' + ", age=" + age + '}';}@Overridepublic boolean equals(Object o) {if (this == o) return true;if (o == null || getClass() != o.getClass()) return false;Person person = (Person) o;return Objects.equals(id, person.id) &&Objects.equals(name, person.name);}@Overridepublic int hashCode() {return Objects.hash(id, name);}}

String的hashCode( )

String有hash這個實例變量,它的定義如下:

private int hash; // Default to 0

它緩存了hashCode()方法的值,也就是說,第一次調用hashCode()的時候,會把結果保存在hash這個變量中,以后再調用就直接返回保存的值。

我們來看下String類的hashCode方法,代碼如下:

public int hashCode() {int h = hash;if (h == 0 && value.length > 0) {char val[] = value;for (int i = 0; i < value.length; i++) {h = 31 * h + val[i];}hash = h;}return h; }

如果緩存的hash不為0,就直接返回了,否則根據字符數組中的內容計算hash,計算方法是:

s[0]?31(n?1)+s[1]?31(n?2)+?+s[n?1]?30s[0]*31^{(n-1)} + s[1]*31^{(n-2)} + \cdots + s[n-1] * 3^0s[0]?31(n?1)+s[1]?31(n?2)+?+s[n?1]?30

s表示字符串,s[0]表示第一個字符,n表示字符串長度,s[0]?31(n?1)s[0]*31^{(n-1)}s[0]?31(n?1)表示31的n-1次方再乘以第一個字符的值。

為什么要用這個計算方法呢?這個式子中,hash值與每個字符的值有關,每個位置乘以不同的值,hash值與每個字符的位置也有關。使用31大概是因為兩個原因,一方面可以產生更分散的散列,即不同字符串hash值也一般不同,另一方面計算效率比較高,31* h 與 32 * h - h 即 (h<<5)-h 等價,可以用更高效率的移位和減法操作代替乘法操作。

在Java中,普遍采用以上思路來實現hashCode,也就是所謂的"33-Times"算法,多看源碼,其實Java很多地方都是這樣的思路。

總結

以上是生活随笔為你收集整理的【Java】浅析equals()和hashCode()的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。