1. 程式人生 > >Java--什麼時候需要重寫equals方法?為什麼重寫equals方法,一定要重寫HashCode方法?

Java--什麼時候需要重寫equals方法?為什麼重寫equals方法,一定要重寫HashCode方法?

何時需要重寫equals()

當一個類有自己特有的“邏輯相等”概念(不同於物件身份的概念)。

設計equals()

[1]使用instanceof操作符檢查“實參是否為正確的型別”。
[2]對於類中的每一個“關鍵域”,檢查實參中的域與當前物件中對應的域值。
[2.1]對於非float和double型別的原語型別域,使用==比較;
[2.2]對於物件引用域,遞迴呼叫equals方法;
[2.3]對於float域,使用Float.floatToIntBits(afloat)轉換為int,再使用==比較;
[2.4]對於double域,使用Double.doubleToLongBits(adouble) 轉換為int,再使用==比較;
[2.5]對於陣列域,呼叫Arrays.equals方法。

當改寫equals()的時候,總是要改寫hashCode()

根據一個類的equals方法(改寫後),兩個截然不同的例項有可能在邏輯上是相等的,但是,根據Object.hashCode方法,它們僅僅是兩個物件。因此,違反了“相等的物件必須具有相等的雜湊碼”。

設計hashCode()

[1]把某個非零常數值,例如17,儲存在int變數result中;
[2]對於物件中每一個關鍵域f(指equals方法中考慮的每一個域):
[2.1]boolean型,計算(f ? 0 : 1);
[2.2]byte,char,short型,計算(int);
[2.3]long型,計算(int) (f ^ (f>>>32));
[2.4]float型,計算Float.floatToIntBits(afloat);
[2.5]double型,計算Double.doubleToLongBits(adouble)得到一個long,再執行[2.3];
[2.6]物件引用,遞迴呼叫它的hashCode方法;
[2.7]陣列域,對其中每個元素呼叫它的hashCode方法。
[3]將上面計算得到的雜湊碼儲存到int變數c,然後執行 result=37*result+c;
[4]返回result。

為什麼重寫equals方法,一定要重寫HashCode方法?

如果你過載了equals,比如說是基於物件的內容實現的,而保留hashCode的實現不變,那麼很可能某兩個物件明明是“相等”,而hashCode卻不一樣。這樣,當你用其中的一個作為鍵儲存到hashMap、hasoTable或hashSet中,再以“相等的”找另一個作為鍵值去查詢他們的時候,則根本找不到。
使用HashMap,如果key是自定義的類,就必須重寫hashcode()和equals()。
而對於每一個物件,通過其hashCode()方法可為其生成一個整形值(雜湊碼),該整型值被處理後,將會作為陣列下標,存放該物件所對應的Entry(存放該物件及其對應值)。 equals()方法則是在HashMap中插入值或查詢時會使用到。當HashMap中插入值或查詢值對應的雜湊碼與陣列中的雜湊碼相等時,則會通過equals方法比較key值是否相等,所以想以自建物件作為HashMap的key,必須重寫該物件繼承object的hashCode和equals方法。

本來不就有hashcode()和equals()了麼?幹嘛要重寫,直接用原來的不行麼?

HashMap中,如果要比較key是否相等,要同時使用這兩個函式!因為自定義的類的hashcode()方法繼承於Object類,其hashcode碼為預設的記憶體地址,這樣即便有相同含義的兩個物件,比較也是不相等的,例如,生成了兩個“羊”物件,正常理解這兩個物件應該是相等的,但如果你不重寫 hashcode()方法的話,比較是不相等的!
HashMap中的比較key是這樣的,先求出key的hashcode(),比較其值是否相等,若相等再比較equals(),若相等則認為他們是相等的。若equals()不相等則認為他們不相等。如果只重寫hashcode()不重寫equals()方法,當比較equals()時只是看他們是否為同一物件(即進行記憶體地址的比較),所以必定要兩個方法一起重寫。HashMap用來判斷key是否相等的方法,其實是呼叫了HashSet判斷加入元素是否相等。

引用別人說的一段話哈~
一般來說,如果你要把一個類的物件放入容器中,那麼通常要為其重寫equals()方法,讓他們比較內容值而不是地址值。特別地,如果要把你的類的物件放入雜湊中,那麼還要重寫hashCode()方法;要放到有序容器中,還要重寫compareTo()方法。
equals()相等的兩個物件,hashcode()一定相等;
equals()不相等的兩個物件,卻並不能證明他們的hashcode()不相等。換句話說,equals()方法不相等的兩個物件,hashcode()有可能相等。(我的理解是由於雜湊碼在生成的時候產生衝突造成的)。
反過來:hashcode()不等,一定能推出equals()也不等;hashcode()相等,equals()可能相等,也可能不等

示例

下面的這個類遵循上面的設計原則,重寫了類的equals()和hashCode():

package com.zj.unit;
import java.util.Arrays;

public class Unit {
    private short ashort;
    private char achar;
    private byte abyte;
    private boolean abool;
    private long along;
    private float afloat;
    private double adouble;
    private Unit aObject;
    private int[] ints;
    private Unit[] units;

    public boolean equals(Object o) {
       if (!(o instanceof Unit))
           return false;
       Unit unit = (Unit) o;
       return unit.ashort == ashort
              && unit.achar == achar
              && unit.abyte == abyte
              && unit.abool == abool
              && unit.along == along
              && Float.floatToIntBits(unit.afloat) == Float
                     .floatToIntBits(afloat)
              && Double.doubleToLongBits(unit.adouble) == Double
                     .doubleToLongBits(adouble)
              && unit.aObject.equals(aObject)
&& equalsInts(unit.ints)
              && equalsUnits(unit.units);
    }

    private boolean equalsInts(int[] aints) {
       return Arrays.equals(ints, aints);
    }

    private boolean equalsUnits(Unit[] aUnits) {
       return Arrays.equals(units, aUnits);
    }

    public int hashCode() {
       int result = 17;
       result = 37 * result + (int) ashort;
       result = 37 * result + (int) achar;
       result = 37 * result + (int) abyte;
       result = 37 * result + (abool ? 0 : 1);
       result = 37 * result + (int) (along ^ (along >>> 32));
       result = 37 * result + Float.floatToIntBits(afloat);
       long tolong = Double.doubleToLongBits(adouble);
       result = 37 * result + (int) (tolong ^ (tolong >>> 32));
       result = 37 * result + aObject.hashCode();
       result = 37 * result + intsHashCode(ints);
       result = 37 * result + unitsHashCode(units);
       return result;
    }

    private int intsHashCode(int[] aints) {
       int result = 17;
       for (int i = 0; i < aints.length; i++)
           result = 37 * result + aints[i];
       return result;
    }

    private int unitsHashCode(Unit[] aUnits) {
       int result = 17;
       for (int i = 0; i < aUnits.length; i++)
           result = 37 * result + aUnits[i].hashCode();
       return result;
    }
}

相關推薦

Java--什麼時候需要重寫equals方法?為什麼重寫equals方法一定重寫HashCode方法

何時需要重寫equals() 當一個類有自己特有的“邏輯相等”概念(不同於物件身份的概念)。 設計equals() [1]使用instanceof操作符檢查“實參是否為正確的型別”。 [2]對於類中的每一個“關鍵域”,檢查實參中

Java基礎之重寫equalshashCode和compareTo方法】什麼時候需要重寫重寫equals方法?為什麼重寫equals方法一定重寫HashCode方法

1.何時需要重寫equals() 當一個類有自己特有的“邏輯相等”概念(不同於物件身份的概念)。 2.設計equals() [1]使用instanceof操作符檢查“實參是否為正確的型別”。 [2]對於類中的每一個“關鍵域”,檢查實參中的域與當前物件中對應的域值。 [2

為什麼重寫equals方法一定重寫HashCode方法?(

使用HashMap,如果key是自定義的類,就必須重寫hashcode()和equals()。     1.hashcode()和equals()是在哪裡被用到的?什麼用的?      HashMap是基於雜湊函式,以陣列和連結串列的方式實現的。  而對於每一個物件,通過其hashCode()方法可為其生成一

覆蓋(不是過載)了equals方法一定覆蓋hashCode方法

為了能讓集合框架中的類如HashMap正常工作,必須保證同時覆蓋equals()和hashCode(),而且注意不要由於寫錯了引數型別,而過載了這兩個方法,卻並沒有覆蓋它們,比如:  public boolean equals(Object obj) 寫成了public boolean equals(Cla

為什麼覆蓋equals方法一定覆蓋hashCode方法

兩個物件值相同(x.equals(y) == true),但卻可有不同的hash code,這句話對不對?  兩個物件有相同的hash code,但是值不同(x.equals(y) == false),這句話對不對?  對,hash code相同,說明value在同一個bucket裡面,也可以說是hash衝突

建立一個物件模型的時候為什麼重寫hashCodeequals方法

為了闡明其作用,我們先來假設有如下一個Person類。 class Person { public Person(String name, int age) { this.name = name; this.age = age;

為什麼重寫equals方法一定重寫hashcode方法

重寫了equals方法一定要重寫hashcode方法,原因在於用到hash來提高效率的集合類在插入物件時先比較物件的hashcode是否相同,若相同再比較equals是否相同,若hashcode不同j就不再比較equals。 雜湊表這個資料結構想必大多數人都不陌生,而且

Hibernate中用到聯合主鍵的使用方法為何序列化為何重寫hashcodeequals 方法

聯合主鍵用Hibernate註解對映方式主要有三種: 第一、將聯合主鍵的欄位單獨放在一個類中,該類需要實現java.io.Serializable介面並重寫equals和hascode,再將該類註解為@Embeddable,最後在主類中(該類不包含聯合主鍵類中的欄位)儲存該

HashMap中使用自定義類作為Key時為何重寫HashCodeEquals方法

ide string https object 避免 equals方法 args sys 添加 之前一直不是很理解為什麽要重寫HashCode和Equals方法,才只能作為鍵值存儲在HashMap中。通過下文,可以一探究竟。 首先,如果我們直接用以下的Person類

Java實戰】原始碼解析為什麼覆蓋equals方法時總覆蓋hashCode方法

1、背景知識本文程式碼基於jdk1.8分析,《Java程式設計思想》中有如下描述:另外再看下Object.java對hashCode()方法的說明:/** * Returns a hash code value for the object. This method

Java中複寫equals 方法的同時也複寫hashCode 方法

                object物件中的 public boolean equals(Object obj),對於任何

java併發-問題-為啥我們覆寫了run方法呼叫start方法?

汪老師很有講課很有水平,講的非常清晰而且常常會帶入一些非常重要的知識,建議大家都去聽下,比在QQ群推薦的公開課強的不是一點兩點 我們在啟動一個執行緒時 繼承Thread 覆寫了run方

Java nio 的Channel介面繼承了Closeable為什麼還要有close() 方法

首先Api是這樣給出的: Closeable的close()方法: void close() throws IOException Closes this stream and

從傳統方法到深度學習人臉特徵點定位方法綜述

人臉關鍵點檢測是人臉識別和分析領域中的關鍵一步,它是諸如自動人臉識別、表情分析、三維人臉重建及三維動畫等其它人臉相關問題的前提和突破口。近些年來,深度學習方法由於其自動學習及持續學習能力,已被成功應用到了影象識別與分析、語音識別和自然語言處理等很多領域,且在這些方面都帶來

沒有抽象方法的類可以申明為抽象方法嗎?有抽象方法的類一定申明為抽象類。。

         有抽象方法的類,一定要申明為抽象類,否則,會編譯錯誤,DOS錯誤提示資訊,可能沒有直接說明原因, 但是在類前加上abstract就可以編譯成功。         沒有抽象方法的類,也可以申明為抽象類,這時,這個類不能被例項化。。。

respondsToSelector的相關使用(非常好用的方法一定了解!!!)

-(BOOL) isKindOfClass: classObj 用來判斷是否是某個類或其子類的例項 -(BOOL) isMemberOfClass: classObj 用來判斷是否是某個類的例項 -(BOOL) respondsToSelector: selector

為什麽 jmeter 分布式測試一定設置 java.rmi.server.hostname

gin -a conn master factory sla 所有 ces ref 之前總結了 jmeter 分布式測試的過程,在部署過程中提到,要在 system.properties中配置自己的 IP。 至於為什麽要這麽做,源於這一次 debug 的過程。 運行環境

Java工程師面試時一定避開這些錯誤禁區!

1、只在電腦上練習   如果面試官要考核你的技術,很有可能會要求你在白板上寫程式碼,而不是電腦上。所以,你就不能只在電腦上練習。電腦上的編譯器會自動發現你的語法錯誤,但是白板不會。   拿出筆和紙來練習下如何寫程式碼。如果你自我檢查之後,覺得程式正確,再將它

JAVA重寫equals()方法的同時重寫hashcode()方法

內存地址 his mov bool args 變量 維護 log obj object對象中的 public boolean equals(Object obj),對於任何非空引用值 x 和 y,當且僅當 x 和 y 引用同一個對象時,此方法才返回 true;註意:當此方法