成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

重寫Equals方法為什么通常會重寫Hashcode方法?

開發 前端
最近在面試的時候,當問完了HashMap的數據結構之后,通常會再多問一個問題,就是:重寫equals方法時通常為什么也要重寫一下hashcode方法?

[[388535]]

本文轉載自微信公眾號「程序新視界」,作者二師兄。轉載本文請聯系程序新視界公眾號。  

最近在面試的時候,當問完了HashMap的數據結構之后,通常會再多問一個問題,就是:重寫equals方法時通常為什么也要重寫一下hashcode方法?

其實這個問題,本質上又回到HashMap的應用場景了,就是想看一下面試者是否真的融會貫通。今天這篇文章就帶大家了解一下equals方法和hashcode方法之間的關系,以及相關的知識點。

equals與hashcode的存在

其實每個類都有一個equals方法和hashcode方法。因為所有的類都繼承自Object類。Object類中定義如下:

  1. public boolean equals(Object obj) { 
  2.     return (this == obj); 
  3.      
  4. public native int hashCode(); 

直觀上可以看到equals方法默認比較的是對象的引用,直接用“==”進行比較。而hashCode方法是一個native方法,返回值為整型。

而這兩個方法都未被final修飾,都是可以進行重寫的。

對于我們經常使用的比如String 、Math、Integer、Double等類,都進行了equals()和hashCode()方法的重寫。

equals()方法

equals()方法是用來判斷兩個對象是否相等。Object默認實現了equals方法,但很明顯不太符合個性化的需求,因此往往需要進行重寫。比如常用的String類,重寫的equals方法如下:

  1. // 重寫equals方法 
  2. public boolean equals(Object anObject) { 
  3.     if (this == anObject) { 
  4.         return true
  5.     } 
  6.     if (anObject instanceof String) { 
  7.         String anotherString = (String)anObject; 
  8.         int n = value.length; 
  9.         if (n == anotherString.value.length) { 
  10.             char v1[] = value; 
  11.             char v2[] = anotherString.value; 
  12.             int i = 0; 
  13.             while (n-- != 0) { 
  14.                 if (v1[i] != v2[i]) 
  15.                     return false
  16.                 i++; 
  17.             } 
  18.             return true
  19.         } 
  20.     } 
  21.     return false

這里的比較已不再是單純的地址比較了。首先通過地址進行比較,如果地址相同那么肯定是相同的對象。如果地址不同就再拿char數組的內容進行比較,完全相等則返回true。

equals()方法的特質

在Object類的equals方法上有注釋說明了equals()方法需滿足的一些特性:

  • 自反性(reflexive)。對于任意不為null的引用值x,x.equals(x)一定是true;
  • 對稱性(symmetric)。對于任意不為null的引用值x和y,當且僅當x.equals(y)是true時,y.equals(x)也是true;
  • 傳遞性(transitive)。對于任意不為null的引用值x、y和z,如果x.equals(y)是true,同時y.equals(z)是true,那么x.equals(z)一定是true;
  • 一致性(consistent)。對于任意不為null的引用值x和y,如果用于equals比較的對象信息沒有被修改的話,多次調用時x.equals(y)要么一致地返回true要么一致地返回false;
  • 對于任意不為null的引用值x,x.equals(null)返回false;

對照上面特質,我們發現Object方法直接比較的是兩個引用地址,只有兩個地址相同才相等,也就是說是差別可能性最大的等價關系。

而String的equals方法,不僅包含應用地址相同這種情況,還包括里面所存儲的字符串值相同的情況。也就是說雖然是兩個String對象,但是它們的字符串值相等,那么equals方法返回的結果就是true。這也正是大多數情況下我們所說的“equals方法比較的是值”。

由于Object的equals方法的默認特例存在,因此在沒有自定義equals方法時,我們不能一概的說equals方法比較的是具體的值,而“==”比較的是引用。

hashCode()方法

hashCode()方法返回對象的一個hash code值。該方法被用于hash tables,如HashSet、HashMap。

hashCode()是一個native方法,返回值類型是整形,并且可以被重寫。

Object中的native hashCode()方法將對象在內存中的地址作為哈希碼返回,可以保證不同對象的返回值不同。

還以String類為例,它的hashCode方法為:

  1. // 重寫hashCode方法 
  2. public int hashCode() { 
  3.     int h = hash; 
  4.     if (h == 0 && value.length > 0) { 
  5.         char val[] = value; 
  6.  
  7.         for (int i = 0; i < value.length; i++) { 
  8.             h = 31 * h + val[i]; 
  9.         } 
  10.         hash = h; 
  11.     } 
  12.     return h; 

上述hash值的計算注釋中有說明,基本公式為:s[0]*31^(n-1) + s[1]*31^(n-2) + … + s[n-1]。

其中, s[i]是字符串的第i個字符,n是字符串的長度,^表示求冪(空字符串的哈希碼為0)。

計算過程中使用數字31,主要有以下原因:

1、由于質數的特性,它與其他數字相乘之后,計算結果唯一的概率更大,哈希沖突的概率更小。

2、使用的質數越大,哈希沖突的概率越小,但是計算的速度也越慢;31是哈希沖突和性能的折中,實際上是實驗觀測的結果。

3、JVM會自動對31進行優化:31 * i == (i << 5) - i;

hashCode()方法的作用

前面提到hashCode()方法主要用于hash表中,比如HashSet、HashMap等。

我們先來看一下ArrayList,它的底層是數組,每個數據往底層的數組中存取即可,數據不需要判斷是否重復。

集合Set中的元素是無序不可重復的,那么如何確保存入的元素不重復呢?逐個調用equals()方法進行比較?數據量少的時候還可以,但數據量大了時間復雜度基本上是O(n),會出現性能問題。

Java中采用哈希算法來解決這個問題,將對象(或數據)依特定算法直接映射到一個地址上,這樣時間復雜度趨于O(1),對象的存取效率大大提高。

集合Set添加某元素時,先調用hashCode()方法,定位到此元素實際存儲位置,如果這個位置沒有元素,說明是第一次存儲;若此位置有對象存在,調用equals()進行比較,相等就舍棄此元素不存,不等則散列到其他地址。

上面的示例也說明了為什么equals()相等,則hashCode()必須相等,進而當重寫了equals方法,也要對hashCode()方法進行重寫。

HashMap的基本處理機制與HashSet很類似,只不過底層的數據存儲結構有所不同而已。

簡而言之,在集合查找時,hashcode能極大的降低對象比較次數,提高查找效率。

hashCode()方法的性質

hashCode的實現也有一定的要求,相關英文說明在Object的equals方法注解上:

  • 在一個Java應用的執行期間,如果一個對象提供給equals做比較的信息沒有被修改的話,該對象多次調用hashCode()方法,該方法必須始終如一返回同一個integer。
  • 如果兩個對象根據equals(Object)方法是相等的,那么調用二者各自的hashCode()方法必須產生同一個integer結果。
  • 并不要求根據equals(java.lang.Object)方法不相等的兩個對象,調用二者各自的hashCode()方法必須產生不同的integer結果。但對于不同的對象產生不同的integer結果,有可能會提高hash table的性能。

如何重寫hashCode()

《Effective Java》中提供了一種簡單通用的hashCode算法。

A、初始化一個整形變量,為此變量賦予一個非零的常數值,比如int result = 17;

B、選取equals方法中用于比較的所有域(之所以只選擇equals()中使用的域,是為了保證上述原則的第1條),然后針對每個域的屬性進行計算:

  • (1) 如果是boolean值,則計算f ? 1:0
  • (2) 如果是byte\char\short\int,則計算(int)f
  • (3) 如果是long值,則計算(int)(f ^ (f >>> 32))
  • (4) 如果是float值,則計算Float.floatToIntBits(f)
  • (5) 如果是double值,則計算Double.doubleToLongBits(f),然后返回的結果是long,再用規則(3)去處理long,得到int
  • (6) 如果是對象應用,如果equals方法中采取遞歸調用的比較方式,那么hashCode中同樣采取遞歸調用hashCode的方式。否則需要為這個域計算一個范式,比如當這個域的值為null的時候,那么hashCode 值為0
  • (7) 如果是數組,那么需要為每個元素當做單獨的域來處理。java.util.Arrays.hashCode方法包含了8種基本類型數組和引用數組的hashCode計算,算法同上。

C、最后,把每個域的散列碼合并到對象的哈希碼中。

小結

關于equals方法很明確的是用于比較兩個對象是否相等。而對于hashCode方法重點是為了在類似HashMap場景下提升效率,只算是技術要求。

在集合中通常通過equals方法來比較對象是否相等,通過hashCode方法來解決大數據量時會發生的性能問題。

在實踐中我們很少使用Object對象來作為Map的key,也是因為如果Object對象的屬性變了,會導致hashCode變化,進而可能會導致找不到對應值,而String是不可變的對象,作為key就很適合。

參考文章:

https://www.cnblogs.com/kismetv/p/7191736.html

https://www.iteye.com/blog/kakajw-935226

https://www.iteye.com/blog/bijian1013-1972404

責任編輯:武曉燕 來源: 程序新視界
相關推薦

2021-07-30 09:32:55

JavaEquals

2019-08-16 10:10:07

hashcodeequalsJava

2021-12-03 06:59:23

HashCodeEquals面試

2021-12-13 09:10:48

equalshashCodeJava

2023-10-08 07:13:19

equalshashCode哈希表

2021-07-13 06:42:58

JavaEquals方法

2009-10-13 14:38:15

.NET重寫URL

2022-01-11 06:53:23

面試重寫重載

2021-01-26 12:14:40

Windows 10Windows微軟

2021-12-30 19:36:48

GoDubboJava

2022-01-07 14:05:33

DubboGoJava

2015-10-10 10:36:00

warning category

2009-12-30 15:26:02

Silverlight

2009-09-04 11:35:05

C#方法重寫

2015-07-28 10:28:54

程序員代碼

2018-05-07 15:59:39

代碼程序員重寫

2015-07-27 15:27:11

程序員重寫代碼

2021-04-08 11:46:41

String hashJava代碼

2019-11-08 13:57:53

程序員Excel軟件

2022-12-28 09:10:44

HashMapImmutable類型
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 日韩精品久久久 | 精品一二三区视频 | 91在线免费视频 | 亚洲国产欧美国产综合一区 | 久久久www成人免费无遮挡大片 | 日韩在线播放网址 | 九九热在线视频 | 在线视频91| 日韩免费一区 | www.99热.com | 免费九九视频 | 欧美日韩一区二区三区四区 | 国产一区二区三区视频在线观看 | 日本不卡一区二区三区在线观看 | 日日欧美 | 91精品久久久久久久久 | 久久国产精品免费一区二区三区 | 久久久成人精品 | 成人免费视频观看 | 国内精品一区二区三区 | 久久精品网 | 久久久久久亚洲精品不卡 | 宅男伊人 | 国产成人精品网站 | 亚洲成人在线视频播放 | 视频一区二区中文字幕日韩 | 91精品国产乱码久久久久久久久 | 精品久久久久国产 | 久久久久国产 | 另类专区亚洲 | 老牛影视av一区二区在线观看 | 国产成人a亚洲精品 | 欧美视频一区二区三区 | 亚洲精久| 中文字字幕一区二区三区四区五区 | 国产精品女人久久久 | 91资源在线 | 日本 欧美 国产 | 少妇一级淫片aaaaaaaaa | 久久久久久91 | 一本岛道一二三不卡区 |