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

java中hashCode、equals的使用方法教程

 更新時(shí)間:2017年12月26日 10:34:37   作者:神秘的寇先森  
hashCode()和equals()定義在Object類中,這個(gè)類是所有java類的基類,所以所有的java類都繼承這兩個(gè)方法。下面這篇文章主要給大家介紹了關(guān)于java中hashCode、equals的使用方法,需要的朋友可以參考下。

前言

眾所周知Java.lang.Object 有一個(gè)hashCode()和一個(gè)equals()方法,這兩個(gè)方法在軟件設(shè)計(jì)中扮演著舉足輕重的角色。在一些類中重寫這兩個(gè)方法以完成某些重要功能。

1、為什么要用 hashCode()?

集合Set中的元素是無序且不可重復(fù)的,那判斷兩個(gè)元素是否重復(fù)的依據(jù)是什么呢?

有人說:比較對(duì)象是否相等當(dāng)然用Object.equal()了。但是,Set中存在大量對(duì)象,后添加到集合Set中的對(duì)象元素比較次數(shù)會(huì)逐漸增多,大大降低了程序運(yùn)行效率。 Java中采用哈希算法(也叫散列算法)來解決這個(gè)問題,將對(duì)象(或數(shù)據(jù))依特定算法直接映射到一個(gè)地址上,對(duì)象的存取效率大大提高。

這樣一來,當(dāng)含有海量元素的集合Set需要添加某元素(對(duì)象)時(shí),先調(diào)用這個(gè)元素的hashCode(),就能一下子定位到此元素實(shí)際存儲(chǔ)位置,如果這個(gè)位置沒有元素,說明此對(duì)象是第一次存儲(chǔ)到集合Set, 直接將此對(duì)象存儲(chǔ)在此位置上;若此位置有對(duì)象存在,調(diào)用equal()看看這兩個(gè)對(duì)象是否相等,相等就舍棄此元素不存,不等則散列到其他地址。

這也是為什么set集合存儲(chǔ)對(duì)象類型數(shù)據(jù)的時(shí)候,要不僅僅重寫對(duì)象的hashCode()方法還要重寫equals()方法的原因。

2、HOW use hashCode()?

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

  • 如果a.equals(b)返回“true”,那么a和b的hashCode()一定相等。
  • 如果a.equals(b)返回“false”,那么a和b的hashCode()有可能相等,也有可能不等。

下面是一個(gè)例子。在實(shí)際的軟件開發(fā)中,最好重寫這兩個(gè)方法。

public class Employee {
 int  employeeId;
 String  name;
 @Override
 public boolean equals(Object obj)
 {
  if(obj==this)
   return true;
  Employee emp=(Employee)obj;
  if(employeeId.equals(emp.getEmployeeId()) && name==emp.getName())
   return true;
  return false;
 }
 @Override
 public int hashCode() {
  int hash = 1;
  hash = hash * 17 + employeeId;
  hash = hash * 31 + name.hashCode();
  return hash;
 }
}

equals()和hashCode()方法是用來在同一類中做比較用的,尤其是在容器里如set存放同一類對(duì)象時(shí)用來判斷放入的對(duì)象是否重復(fù)。

這里我們首先要明白一個(gè)問題:

equals()相等的兩個(gè)對(duì)象,hashcode()一定相等,equals()不相等的兩個(gè)對(duì)象,卻并不能證明他們的hashcode()不相等。換句話說,equals()方法不相等的兩個(gè)對(duì)象,hashCode()有可能相等。

在這里hashCode就好比字典里每個(gè)字的索引,equals()好比比較的是字典里同一個(gè)字下的不同詞語。就好像在字典里查“自”這個(gè)字下的兩個(gè)詞語“自己”、“自發(fā)”,如果用equals()判斷查詢的詞語相等那么就是同一個(gè)詞語,比如equals()比較的兩個(gè)詞語都是“自己”,那么此時(shí)hashCode()方法得到的值也肯定相等;如果用equals()方法比較的是“自己”和“自發(fā)”這兩個(gè)詞語,那么得到結(jié)果是不想等,但是這兩個(gè)詞都屬于“自”這個(gè)字下的詞語所以在查索引時(shí)相同,即:hashCode()相同。如果用equals()比較的是“自己”和“他們”這兩個(gè)詞語的話那么得到的結(jié)果也是不同的,此時(shí)hashCode() 得到也是不同的。

反過來:hashcode()不等,一定能推出equals()也不等;hashcode()相等,equals()可能相等,也可能不等。

在object類中,hashcode()方法是本地方法,返回的是對(duì)象的地址值,而object類中的equals()方法比較的也是兩個(gè)對(duì)象的地址值,如果equals()相等,說明兩個(gè)對(duì)象地址值也相等,當(dāng)然hashcode() 也就相等了。

既然equals比較元素相等更準(zhǔn)確,那么為什么還要用hashCode( )方法呢?

因?yàn)閔ash算法對(duì)于查找元素提供了很高的效率,如果想查找一個(gè)集合中是否包含有某個(gè)對(duì)象,大概的程序代碼怎樣寫呢?
你通常是逐一取出每個(gè)元素與要查找的對(duì)象進(jìn)行比較,當(dāng)發(fā)現(xiàn)某個(gè)元素與要查找的對(duì)象進(jìn)行equals方法比較的結(jié)果相等時(shí),則停止繼續(xù)查找并返回肯定的信息,否則,返回否定的信息,如果一個(gè)集合中有很多個(gè)元素,比如有一萬個(gè)元素,并且沒有包含要查找的對(duì)象時(shí),則意味著你的程序需要從集合中取出一萬個(gè)元素進(jìn)行逐一比較才能得到結(jié)論。

Object類中定義了一個(gè)hashCode()方法來返回每個(gè)Java對(duì)象的哈希碼,當(dāng)從HashSet集合中查找某個(gè)對(duì)象時(shí),Java系統(tǒng)首先調(diào)用對(duì)象的hashCode()方法獲得該對(duì)象的哈希碼表,然后根據(jù)哈希嗎找到相應(yīng)的存儲(chǔ)區(qū)域,最后取得該存儲(chǔ)區(qū)域內(nèi)的每個(gè)元素與該對(duì)象進(jìn)行equals方法比較;這樣就不用遍歷集合中的所有元素就可以得到結(jié)論,可見,HashSet集合具有很好的對(duì)象檢索性能。

但是,HashSet集合存儲(chǔ)對(duì)象的效率相對(duì)要低些,因?yàn)橄騂ashSet集合中添加一個(gè)對(duì)象時(shí),要先計(jì)算出對(duì)象的哈希碼和根據(jù)這個(gè)哈希碼確定對(duì)象在集合中的存放位置為了保證一個(gè)類的實(shí)例對(duì)象能在HashSet正常存儲(chǔ),要求這個(gè)類的兩個(gè)實(shí)例對(duì)象用equals()方法比較的結(jié)果相等時(shí),他們的哈希碼也必須相等;也就是說,如果obj1.equals(obj2)的結(jié)果為true,那么以下表達(dá)式的結(jié)果也要為true:obj1.hashCode() == obj2.hashCode()

換句話說:當(dāng)我們重寫一個(gè)對(duì)象的equals方法,就必須重寫他的hashCode方法,不重寫他的hashCode方法的話,Object對(duì)象中的hashCode方法始終返回的是一個(gè)對(duì)象的hash地址,而這個(gè)地址是永遠(yuǎn)不相等的。所以這時(shí)候即使是重寫了equals方法,也不會(huì)有特定的效果的,因?yàn)閔ashCode方法如果都不想等的話,就不會(huì)調(diào)用equals方法進(jìn)行比較了,所以沒有意義了。

大多數(shù)的數(shù)據(jù)結(jié)構(gòu)通過equals方法來判斷他們是否包含一個(gè)元素,例如:

List<String> list = Arrays.asList("a", "b", "c");
boolean contains = list.contains("b");

這個(gè)變量contains結(jié)果是true,因?yàn)?雖然”b”是不相同的實(shí)例(此外,忽略字符串駐留),但是他們是相等的。

他們通過使用一種快捷的方式(減少潛在的實(shí)例相等)進(jìn)行比較,從而代替通過比較實(shí)例所包含的每個(gè)元素。而快捷比較僅需要比較下面這些方面:

快捷方式比較即通過比較哈希值,它可以將一個(gè)實(shí)例用一個(gè)整數(shù)值來代替。哈希碼相同的實(shí)例不一定相等,但相等的實(shí)例一定具有有相同的哈希值。(或應(yīng)該有,我們很快就會(huì)討論這個(gè))這些數(shù)據(jù)結(jié)構(gòu)經(jīng)常通過這種這種技術(shù)來命名,可以通過Hash來識(shí)別他們的,其中,HashMap是其中最著名的代表。

它們通常是這樣這樣運(yùn)作的:

當(dāng)添加一個(gè)元素,它的哈希碼是用來計(jì)算內(nèi)部數(shù)組的索引(即所謂的桶)

如果是,不相等的元素有相同的哈希碼,他們最終在同一個(gè)桶上并且捆綁在一起,例如通過添加到列表。
當(dāng)一個(gè)實(shí)例來進(jìn)行contains操作時(shí),它的哈希碼將用來計(jì)算桶值(索引值),只有當(dāng)對(duì)應(yīng)索引值上存在元素時(shí),才會(huì)對(duì)實(shí)例進(jìn)行比較。

因此equals,hashCode是定義在Object類中。

如果hashCode作為快捷方式來確定相等,那么只有一件事我們應(yīng)該關(guān)心:相等的對(duì)象應(yīng)該具有相同的哈希碼,這也是為什么如果我們重寫了equals方法后,我們必須創(chuàng)建一個(gè)與之匹配的hashCode實(shí)現(xiàn)的原因!

否則相等的對(duì)象是可能不會(huì)有相同的哈希碼的,因?yàn)樗鼈儗⒄{(diào)用的是Object's的默認(rèn)實(shí)現(xiàn)。

引用自官方文檔

hashCode通用約定:

調(diào)用運(yùn)行Java應(yīng)用程序中的同一對(duì)象,hashCode方法必須始終返回相同的整數(shù)。這個(gè)整數(shù)不需要在不同的Java應(yīng)用程序中保持一致。根據(jù)equals(Object)的方法來比較,如果兩個(gè)對(duì)象是相等的,兩個(gè)對(duì)象調(diào)用hashCode方法必須產(chǎn)生相同的結(jié)果。

根據(jù)equals(Object)的方法是比較,如果兩個(gè)對(duì)象是不相等的,那么兩個(gè)對(duì)象調(diào)用hashCode方法并不一定產(chǎn)生不同的整數(shù)的結(jié)果。但是,程序員應(yīng)該意識(shí)到給不相等的對(duì)象產(chǎn)生不同的整數(shù)結(jié)果將有可能提高哈希表的性能。

HashCode實(shí)現(xiàn)

下面是簡(jiǎn)單的person.hashcode()的實(shí)現(xiàn):

@Override
public int hashCode() {
 return Objects.hash(firstName, lastName);
}

person's是通過多個(gè)字段結(jié)合來計(jì)算哈希碼的。都是通過Object的hash函數(shù)來計(jì)算。

選擇字段

但哪些字段是相關(guān)的呢?需求將會(huì)幫助我們回答這個(gè)問題:

如果相等的對(duì)象必須具有相同的哈希碼,那么計(jì)算哈希碼就不應(yīng)包括任何不用于相等檢查的字段。(否則兩個(gè)對(duì)象只是這些字段不同但是仍然有可能會(huì)相等,此時(shí)他們這兩個(gè)對(duì)象哈希碼卻會(huì)不相同。)所以用于哈希組字段應(yīng)該相等時(shí)使用的字段的子集。默認(rèn)情況下都使用相同的字段,但有一些細(xì)節(jié)需要考慮。

總結(jié)

我們了解到計(jì)算哈希碼就是壓縮相等的一個(gè)整數(shù)值:相等的對(duì)象必須有相同的哈希碼,而出于對(duì)性能的考慮:最好是盡可能少的不相等的對(duì)象共享相同的哈希碼。

這就意味著如果重寫了equals方法,那么就必須重寫hashCode方法

當(dāng)實(shí)現(xiàn)hashCode使用與equals中使用的相同的字段(或者equals中使用字段的子集)

最好不要包含可變的字段。對(duì)集合不要考慮調(diào)用hashCode,如果沒有特殊的輸入特定的模式,盡量采用通用的哈希算法

好了,以上就是這篇文章的全部?jī)?nèi)容了,希望本文的內(nèi)容對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,如果有疑問大家可以留言交流,謝謝大家對(duì)腳本之家的支持。

相關(guān)文章

  • Spring MVC簡(jiǎn)介_動(dòng)力節(jié)點(diǎn)Java學(xué)院整理

    Spring MVC簡(jiǎn)介_動(dòng)力節(jié)點(diǎn)Java學(xué)院整理

    Spring MVC屬于SpringFrameWork的后續(xù)產(chǎn)品,已經(jīng)融合在Spring Web Flow里面。今天先從寫一個(gè)Spring MVC的HelloWorld開始,讓我們看看如何搭建起一個(gè)Spring mvc的環(huán)境并運(yùn)行程序,感興趣的朋友一起學(xué)習(xí)吧
    2017-08-08
  • 詳解Spring MVC如何測(cè)試Controller(使用springmvc mock測(cè)試)

    詳解Spring MVC如何測(cè)試Controller(使用springmvc mock測(cè)試)

    這篇文章主要介紹了詳解Spring MVC如何測(cè)試Controller(使用springmvc mock測(cè)試),小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2017-12-12
  • Java中RocketMq的消費(fèi)方式詳解

    Java中RocketMq的消費(fèi)方式詳解

    這篇文章主要介紹了Java中RocketMq的消費(fèi)方式詳解,RocketMQ的消費(fèi)方式都是基于拉模式拉取消息的,而在這其中有一種長(zhǎng)輪詢機(jī)制(對(duì)普通輪詢的一種優(yōu)化),來平衡上面Push/Pull模型的各自缺點(diǎn),需要的朋友可以參考下
    2023-10-10
  • IDEA設(shè)置字體隨鼠標(biāo)滾動(dòng)放大縮小的實(shí)現(xiàn)

    IDEA設(shè)置字體隨鼠標(biāo)滾動(dòng)放大縮小的實(shí)現(xiàn)

    這篇文章主要介紹了IDEA設(shè)置字體隨鼠標(biāo)滾動(dòng)放大縮小的實(shí)現(xiàn)方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2024-01-01
  • java 內(nèi)部類的詳解及實(shí)例

    java 內(nèi)部類的詳解及實(shí)例

    這篇文章主要介紹了 java 內(nèi)部類的詳解及實(shí)例的相關(guān)資料,這里提供了兩種內(nèi)部類的實(shí)現(xiàn)方法,并給出實(shí)例,需要的朋友可以參考下
    2017-08-08
  • Spring中的@ConfigurationProperties在方法上的使用詳解

    Spring中的@ConfigurationProperties在方法上的使用詳解

    這篇文章主要介紹了Spring中的@ConfigurationProperties在方法上的使用詳解,@ConfigurationProperties應(yīng)該經(jīng)常被使用到,作用在類上的時(shí)候,將該類的屬性取值?與配置文件綁定,并生成配置bean對(duì)象,放入spring容器中,提供給其他地方使用,需要的朋友可以參考下
    2024-01-01
  • 詳解Java設(shè)計(jì)模式編程中的Flyweight享元模式的開發(fā)結(jié)構(gòu)

    詳解Java設(shè)計(jì)模式編程中的Flyweight享元模式的開發(fā)結(jié)構(gòu)

    這篇文章主要介紹了Java設(shè)計(jì)模式編程中的Flyweight享元模式的開發(fā)結(jié)構(gòu),享元模式能夠最大限度地重用現(xiàn)有的同類對(duì)象,需要的朋友可以參考下
    2016-04-04
  • MybatisPlus實(shí)現(xiàn)邏輯刪除的示例代碼

    MybatisPlus實(shí)現(xiàn)邏輯刪除的示例代碼

    本文主要介紹了Mybatis?Plus實(shí)現(xiàn)邏輯刪除的示例代碼,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2023-05-05
  • 基于Java的Socket編寫的C/S聊天程序?qū)崿F(xiàn)

    基于Java的Socket編寫的C/S聊天程序?qū)崿F(xiàn)

    這篇文章主要介紹了基于Java的Socket編寫的C/S聊天程序?qū)崿F(xiàn),文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-03-03
  • Springboot實(shí)現(xiàn)緩存預(yù)熱的方法

    Springboot實(shí)現(xiàn)緩存預(yù)熱的方法

    在系統(tǒng)啟動(dòng)之前通過預(yù)先將常用數(shù)據(jù)加載到緩存中,以提高緩存命中率和系統(tǒng)性能的過程,緩存預(yù)熱的目的是盡可能地避免緩存擊穿和緩存雪崩,這篇文章主要介紹了Springboot實(shí)現(xiàn)緩存預(yù)熱,需要的朋友可以參考下
    2024-03-03

最新評(píng)論

白山市| 红桥区| 蒙山县| 保靖县| 大宁县| 资兴市| 裕民县| 日喀则市| 普定县| 凌源市| 安陆市| 旅游| 上虞市| 叙永县| 宜良县| 策勒县| 大石桥市| 来安县| 肥城市| 司法| 读书| 台中县| 右玉县| 金沙县| 江川县| 都匀市| 宜宾县| 崇左市| 上思县| 徐汇区| 五河县| 清河县| 万山特区| 郯城县| 遵化市| 都匀市| 沂源县| 宝坻区| 沈丘县| 乌海市| 确山县|