欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

深入理解equals和hashCode方法

 更新時(shí)間:2019年06月03日 09:10:45   作者:lulipro  
在Java中,equals和hashCode方法是Object中提供的兩個(gè)方法,這兩個(gè)方法對(duì)以后的學(xué)習(xí)有很大的幫助,本文就深度來(lái)去講解這兩個(gè)方法。下面小編帶大家來(lái)一起學(xué)習(xí)吧

前言

在程序設(shè)計(jì)中,有很多的“公約”,遵守約定去實(shí)現(xiàn)你的代碼,會(huì)讓你避開(kāi)很多坑,這些公約是前人總結(jié)出來(lái)的設(shè)計(jì)規(guī)范。

Object類(lèi)是Java中的萬(wàn)類(lèi)之祖,其中,equals和hashCode是2個(gè)非常重要的方法。

這2個(gè)方法總是被人放在一起討論。最近在看集合框架,為了打基礎(chǔ),就決定把一些細(xì)枝末節(jié)清理掉。一次性搞清楚!

下面開(kāi)始剖析。

public boolean equals(Object obj)

Object類(lèi)中默認(rèn)的實(shí)現(xiàn)方式是 : return this == obj 。那就是說(shuō),只有this 和 obj引用同一個(gè)對(duì)象,才會(huì)返回true。

而我們往往需要用equals來(lái)判斷 2個(gè)對(duì)象是否等價(jià),而非驗(yàn)證他們的唯一性。這樣我們?cè)趯?shí)現(xiàn)自己的類(lèi)時(shí),就要重寫(xiě)equals.

按照約定,equals要滿(mǎn)足以下規(guī)則。

  • 自反性: x.equals(x) 一定是true
  • 對(duì)null: x.equals(null) 一定是false
  • 對(duì)稱(chēng)性: x.equals(y) 和 y.equals(x)結(jié)果一致
  • 傳遞性: a 和 b equals , b 和 c equals,那么 a 和 c也一定equals。
  • 一致性: 在某個(gè)運(yùn)行時(shí)期間,2個(gè)對(duì)象的狀態(tài)的改變不會(huì)不影響equals的決策結(jié)果,那么,在這個(gè)運(yùn)行時(shí)期間,無(wú)論調(diào)用多少次equals,都返回相同的結(jié)果。

一個(gè)例子

1 class Test
2 {
3 private int num;
4 private String data;
5 
6 public boolean equals(Object obj)
7 {
8 if (this == obj)
9 return true;
10 
11 if ((obj == null) || (obj.getClass() != this.getClass()))
12 return false;
13 
//能執(zhí)行到這里,說(shuō)明obj和this同類(lèi)且非null。
14 Test test = (Test) obj;
15 return num == test.num&& (data == test.data || (data != null && data.equals(test.data)));
16 }
17 
18 public int hashCode()
19 {
20 //重寫(xiě)equals,也必須重寫(xiě)hashCode。具體后面介紹。
24 }
25 
26 }

equals編寫(xiě)指導(dǎo)

Test類(lèi)對(duì)象有2個(gè)字段,num和data,這2個(gè)字段代表了對(duì)象的狀態(tài),他們也用在equals方法中作為評(píng)判的依據(jù)。

在第8行,傳入的比較對(duì)象的引用和this做比較,這樣做是為了 save time ,節(jié)約執(zhí)行時(shí)間,如果this 和 obj是 對(duì)同一個(gè)堆對(duì)象的引用,那么,他們一定是qeuals 的。

接著,判斷obj是不是為null,如果為null,一定不equals,因?yàn)榧热划?dāng)前對(duì)象this能調(diào)用equals方法,那么它一定不是null,非null 和 null當(dāng)然不等價(jià)。

然后,比較2個(gè)對(duì)象的運(yùn)行時(shí)類(lèi),是否為同一個(gè)類(lèi)。不是同一個(gè)類(lèi),則不equals。getClass返回的是 this 和obj的運(yùn)行時(shí)類(lèi)的引用。如果他們屬于同一個(gè)類(lèi),則返回的是同一個(gè)運(yùn)行時(shí)類(lèi)的引用。注意,一個(gè)類(lèi)也是一個(gè)對(duì)象。

1、有些程序員使用下面的第二種寫(xiě)法替代第一種比較運(yùn)行時(shí)類(lèi)的寫(xiě)法。應(yīng)該避免這樣做。

if((obj == null) || (obj.getClass() != this.getClass())) 
return false;
if(!(obj instanceof Test)) 
return false; // avoid 避免!

它違反了公約中的對(duì)稱(chēng)原則。

例如:假設(shè)Dog擴(kuò)展了Aminal類(lèi)。

dog instanceof Animal 得到true

animal instanceof Dog 得到false

這就會(huì)導(dǎo)致

animal.equls(dog) 返回true
dog.equals(animal) 返回false

僅當(dāng)Test類(lèi)沒(méi)有子類(lèi)的時(shí)候,這樣做才能保證是正確的。

2、按照第一種方法實(shí)現(xiàn),那么equals只能比較同一個(gè)類(lèi)的對(duì)象,不同類(lèi)對(duì)象永遠(yuǎn)是false。但這并不是強(qiáng)制要求的。一般我們也很少需要在不同的類(lèi)之間使用equals。

3、在具體比較對(duì)象的字段的時(shí)候,對(duì)于基本值類(lèi)型的字段,直接用 == 來(lái)比較(注意浮點(diǎn)數(shù)的比較,這是一個(gè)坑)對(duì)于引用類(lèi)型的字段,你可以調(diào)用他們的equals,當(dāng)然,你也需要處理字段為null 的情況。對(duì)于浮點(diǎn)數(shù)的比較,我在看Arrays.binarySearch的源代碼時(shí),發(fā)現(xiàn)了如下對(duì)于浮點(diǎn)數(shù)的比較的技巧:

if ( Double.doubleToLongBits(d1) == Double.doubleToLongBits(d2) ) //d1 和 d2 是double類(lèi)型

if( Float.floatToIntBits(f1) == Float.floatToIntBits(f2) ) //f1 和 f2 是d2是float類(lèi)型

4、并不總是要將對(duì)象的所有字段來(lái)作為equals 的評(píng)判依據(jù),那取決于你的業(yè)務(wù)要求。比如你要做一個(gè)家電功率統(tǒng)計(jì)系統(tǒng),如果2個(gè)家電的功率一樣,那就有足夠的依據(jù)認(rèn)為這2個(gè)家電對(duì)象等價(jià)了,至少在你這個(gè)業(yè)務(wù)邏輯背景下是等價(jià)的,并不關(guān)心他們的價(jià)錢(qián)啊,品牌啊,大小等其他參數(shù)。

5、最后需要注意的是,equals 方法的參數(shù)類(lèi)型是Object,不要寫(xiě)錯(cuò)!

public int hashCode()

這個(gè)方法返回對(duì)象的散列碼,返回值是int類(lèi)型的散列碼。
對(duì)象的散列碼是為了更好的支持基于哈希機(jī)制的Java集合類(lèi),例如 Hashtable, HashMap, HashSet 等。

關(guān)于hashCode方法,一致的約定是:
重寫(xiě)了euqls方法的對(duì)象必須同時(shí)重寫(xiě)hashCode()方法。

如果2個(gè)對(duì)象通過(guò)equals調(diào)用后返回是true,那么這個(gè)2個(gè)對(duì)象的hashCode方法也必須返回同樣的int型散列碼

如果2個(gè)對(duì)象通過(guò)equals返回false,他們的hashCode返回的值允許相同。(然而,程序員必須意識(shí)到,hashCode返回獨(dú)一無(wú)二的散列碼,會(huì)讓存儲(chǔ)這個(gè)對(duì)象的hashtables更好地工作。)

在上面的例子中,Test類(lèi)對(duì)象有2個(gè)字段,num和data,這2個(gè)字段代表了對(duì)象的狀態(tài),他們也用在equals方法中作為評(píng)判的依據(jù)。那么, 在hashCode方法中,這2個(gè)字段也要參與hash值的運(yùn)算,作為hash運(yùn)算的中間參數(shù)。這點(diǎn)很關(guān)鍵,這是為了遵守:2個(gè)對(duì)象equals,那么 hashCode一定相同規(guī)則。

也是說(shuō),參與equals函數(shù)的字段,也必須都參與hashCode 的計(jì)算。

合乎情理的是:同一個(gè)類(lèi)中的不同對(duì)象返回不同的散列碼。典型的方式就是根據(jù)對(duì)象的地址來(lái)轉(zhuǎn)換為此對(duì)象的散列碼,但是這種方式對(duì)于Java來(lái)說(shuō)并不是唯一的要求的
的實(shí)現(xiàn)方式。通常也不是最好的實(shí)現(xiàn)方式。

相比于equals公認(rèn)實(shí)現(xiàn)約定,hashCode的公約要求是很容易理解的。有2個(gè)重點(diǎn)是hashCode方法必須遵守的。約定的第3點(diǎn),其實(shí)就是第2點(diǎn)的
細(xì)化,下面我們就來(lái)看看對(duì)hashCode方法的一致約定要求。

  • 第一:在某個(gè)運(yùn)行時(shí)期間,只要對(duì)象的(字段的)變化不會(huì)影響equals方法的決策結(jié)果,那么,在這個(gè)期間,無(wú)論調(diào)用多少次hashCode,都必須返回同一個(gè)散列碼。
  • 第二:通過(guò)equals調(diào)用返回true 的2個(gè)對(duì)象的hashCode一定一樣。
  • 第三:通過(guò)equasl返回false 的2個(gè)對(duì)象的散列碼不需要不同,也就是他們的hashCode方法的返回值允許出現(xiàn)相同的況。

總結(jié)一句話:等價(jià)的(調(diào)用equals返回true)對(duì)象必須產(chǎn)生相同的散列碼。不等價(jià)的對(duì)象,不要求產(chǎn)生的散列碼不相同。

hashCode編寫(xiě)指導(dǎo)

在編寫(xiě)hashCode時(shí),你需要考慮的是,最終的hash是個(gè)int值,而不能溢出。不同的對(duì)象的hash碼應(yīng)該盡量不同,避免hash沖突。

那么如果做到呢?下面是解決方案。

1、定義一個(gè)int類(lèi)型的變量 hash,初始化為 7。

接下來(lái)讓你認(rèn)為重要的字段(equals中衡量相等的字段)參入散列運(yùn),算每一個(gè)重要字段都會(huì)產(chǎn)生一個(gè)hash分量,為最終的hash值做出貢獻(xiàn)(影響)

運(yùn)算方法參考表

重要字段var的類(lèi)型 他生成的hash分量
byte, char, short , int (int)var
long  (int)(var ^ (var >>> 32))
boolean var?1:0
float  Float.floatToIntBits(var)
 double  long bits = Double.doubleToLongBits(var);
分量 = (int)(bits ^ (bits >>> 32));
 引用類(lèi)型   (null == var ? 0 : var.hashCode())

 最后把所有的分量都總和起來(lái),注意并不是簡(jiǎn)單的相加。選擇一個(gè)倍乘的數(shù)字31,參與計(jì)算。然后不斷地遞歸計(jì)算,直到所有的字段都參與了。

int hash = 7;
hash = 31 * hash + 字段1貢獻(xiàn)分量;
hash = 31 * hash + 字段2貢獻(xiàn)分量;
.....
return hash;

說(shuō)明,以下的內(nèi)容是我在google上找到并翻譯整理的,其中加入了自己的話和一些例子,便于理解,但我能保證這并不影響整體準(zhǔn)確性。

英文原文:http://www.javaranch.com/journal/2002/10/equalhash.html

以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。

相關(guān)文章

  • 淺談Java方法調(diào)用的優(yōu)先級(jí)問(wèn)題

    淺談Java方法調(diào)用的優(yōu)先級(jí)問(wèn)題

    這篇文章主要介紹了淺談Java方法調(diào)用的優(yōu)先級(jí)問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2020-10-10
  • java字符串切割實(shí)例學(xué)習(xí)(獲取文件名)

    java字符串切割實(shí)例學(xué)習(xí)(獲取文件名)

    在Java中處理一些路徑相關(guān)的問(wèn)題的時(shí)候,如要取出ie瀏覽器上傳文件的文件名,由于ie會(huì)把整個(gè)文件路徑都作為文件名上傳,需要用java.lang.String中的replaceAll或者split來(lái)處理,下面看看使用方法
    2013-12-12
  • Java設(shè)計(jì)模式之工廠模式案例詳解

    Java設(shè)計(jì)模式之工廠模式案例詳解

    工廠模式(Factory Pattern)是Java中最常用的設(shè)計(jì)模式之一。這種類(lèi)型的設(shè)計(jì)模式屬于創(chuàng)建型模式,它提供了一種創(chuàng)建對(duì)象的最佳方式。本文將通過(guò)案例詳細(xì)講解一下工廠模式,需要的可以參考一下
    2022-02-02
  • Java原子操作CAS原理解析

    Java原子操作CAS原理解析

    這篇文章主要介紹了Java原子操作CAS原理解析,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2019-10-10
  • Java Spring Bean的生命周期管理詳解

    Java Spring Bean的生命周期管理詳解

    這篇文章主要為大家介紹了Java Spring Bean的生命周期管理,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下,希望能夠給你帶來(lái)幫助
    2021-12-12
  • Callable實(shí)現(xiàn)多線程步驟詳解

    Callable實(shí)現(xiàn)多線程步驟詳解

    這篇文章主要介紹了Callable實(shí)現(xiàn)多線程步驟詳解,Callable是一個(gè)接口,用于實(shí)現(xiàn)多線程,與實(shí)現(xiàn)Runnable類(lèi)似,但是功能更強(qiáng)大,該方法可以在任務(wù)結(jié)束后提供一個(gè)返回值,需要的朋友可以參考下
    2023-10-10
  • Mybatis攔截器實(shí)現(xiàn)一種百萬(wàn)級(jí)輕量分表方案

    Mybatis攔截器實(shí)現(xiàn)一種百萬(wàn)級(jí)輕量分表方案

    這篇文章主要介紹了Mybatis攔截器實(shí)現(xiàn)一種百萬(wàn)級(jí)輕量分表方案,需要的朋友可以參考下
    2024-02-02
  • Java并發(fā) CompletableFuture異步編程的實(shí)現(xiàn)

    Java并發(fā) CompletableFuture異步編程的實(shí)現(xiàn)

    這篇文章主要介紹了Java并發(fā) CompletableFuture異步編程的實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2020-01-01
  • Java語(yǔ)言面向?qū)ο缶幊趟枷胫?lèi)與對(duì)象實(shí)例詳解

    Java語(yǔ)言面向?qū)ο缶幊趟枷胫?lèi)與對(duì)象實(shí)例詳解

    這篇文章主要介紹了Java語(yǔ)言面向?qū)ο缶幊趟枷胫?lèi)與對(duì)象實(shí)例詳解,還是十分不錯(cuò)的,這里給大家分享下,需要的朋友可以參考。
    2017-10-10
  • GC算法實(shí)現(xiàn)篇之并發(fā)標(biāo)記清除

    GC算法實(shí)現(xiàn)篇之并發(fā)標(biāo)記清除

    這篇文章主要為大家介紹了GC算法實(shí)現(xiàn)篇之并發(fā)-標(biāo)記-清除,?CMS垃圾收集器在減少停頓時(shí)間上做了很多給力的工作,?大量的并發(fā)線程執(zhí)行的工作并不需要暫停應(yīng)用線程
    2022-01-01

最新評(píng)論