HashCode和hashMap、hashTable

2019獨角獸企業重金招聘Python工程師標準>>> hot3.png

什么是哈希碼(HashCode)

在Java中,哈希碼代表對象的特征。

例如對象 String str1 = “aa”, str1.hashCode= 3104

String str2 = “bb”, str2.hashCode= 3106

String str3 = “aa”, str3.hashCode= 3104

根據HashCode由此可得出str1!=str2,str1==str3

下面給出幾個常用的哈希碼的算法。

1:Object類的hashCode.返回對象的內存地址經過處理后的結構,由于每個對象的內存地址都不一樣,所以哈希碼也不一樣。

2:String類的hashCode.根據String類包含的字符串的內容,根據一種特殊算法返回哈希碼,只要字符串所在的堆空間相同,返回的哈希碼也相同。

3:Integer類,返回的哈希碼就是Integer對象里所包含的那個整數的數值,例如Integer i1=new Integer(100),i1.hashCode的值就是100 。由此可見,2個一樣大小的Integer對象,返回的哈希碼也一樣。


HashSet和HashMap一直都是JDK中最常用的兩個類,HashSet要求不能存儲相同的對象,HashMap要求不能存儲相同的鍵。 ?

那么Java運行時環境是如何判斷HashSet中相同對象、HashMap中相同鍵的呢?當存儲了“相同的東西”之后Java運行時環境又將如何來維護呢? ??

在研究這個問題之前,首先說明一下JDK對equals(Object obj)和hashcode()這兩個方法的定義和規范: ?

在Java中任何一個對象都具備equals(Object obj)和hashcode()這兩個方法,因為他們是在Object類中定義的。 ?

equals(Object obj)方法用來判斷兩個對象是否“相同”,如果“相同”則返回true,否則返回false。 ?

hashcode()方法返回一個int數,在Object類中的默認實現是“將該對象的內部地址轉換成一個整數返回”。 ?

接下來有兩個個關于這兩個方法的重要規范(我只是抽取了最重要的兩個,其實不止兩個):?

?規范1:若重寫equals(Object obj)方法,有必要重寫hashcode()方法,確保通過equals(Object obj)方法判斷結果為true的兩個對象具備相等的hashcode()返回值。說得簡單點就是:“如果兩個對象相同,那么他們的hashcode應該 相等”。不過請注意:這個只是規范,如果你非要寫一個類讓equals(Object obj)返回true而hashcode()返回兩個不相等的值,編譯和運行都是不會報錯的。不過這樣違反了Java規范,程序也就埋下了BUG。?

?規范2:如果equals(Object obj)返回false,即兩個對象“不相同”,并不要求對這兩個對象調用hashcode()方法得到兩個不相同的數。說的簡單點就是:“如果兩個對象不相同,他們的hashcode可能相同”。 ?

根據這兩個規范,可以得到如下推論: ?

1、如果兩個對象equals,Java運行時環境會認為他們的hashcode一定相等。?

?2、如果兩個對象不equals,他們的hashcode有可能相等。 ?

3、如果兩個對象hashcode相等,他們不一定equals。 ?

4、如果兩個對象hashcode不相等,他們一定不equals。 ??

這樣我們就可以推斷Java運行時環境是怎樣判斷HashSet和HastMap中的兩個對象相同或不同了。我的推斷是:先判斷hashcode是否相等,再判斷是否equals。

測試程序如下:首先我們定義一個類,重寫hashCode()和equals(Object obj)方法?

?class?A?{???????????@Override?????public?boolean?equals(Object?obj)?{System.out.println("判斷equals");?return?false;?????????}???????????@Override?????public?int?hashCode()?{?????System.out.println("判斷hashcode");?????return?1;??????????}?????}

然后寫一個測試類,代碼如下:

public?class?Test?{???????????public?static?void?main(String[]?args)?{?????Map<A,Object>?map?=?new?HashMap<A,?Object>();map.put(new?A(),?new?Object());map.put(new?A(),?new?Object());??????????????System.out.println(map.size());}
}

運行之后打印結果是: ??

判斷hashcode?

判斷hashcode ?

判斷equals?


HashCode的作用

首先,想要明白hashCode的作用,你必須要先知道Java中的集合。
  總的來說,Java中的集合(Collection)有兩類,一類是List,再有一類是Set。你知道它們的區別嗎?前者集合內的元素是有序的,元素可以重復;后者元素無序,但元素不可重復。那么這里就有一個比較嚴重的問題了:要想保證元素不重復,可兩個元素是否重復應該依據什么來判斷呢?這就是Object.equals方法了。但是,如果每增加一個元素就檢查一次,那么當元素很多時,后添加到集合中的元素比較的次數就非常多了。也就是說,如果集合中現在已經有1000個元素,那么第1001個元素加入集合時,它就要調用1000次equals方法。這顯然會大大降低效率。
????于是,Java采用了哈希表的原理。哈希(Hash)實際上是個人名,由于他提出一哈希算法的概念,所以就以他的名字命名了。哈希算法也稱為散列算法,是將數據依特定算法直接指定到一個地址上。如果詳細講解哈希算法,那需要更多的文章篇幅,我在這里就不介紹了。初學者可以這樣理解,hashCode方法實際上返回的就是對象存儲的物理地址(PS:這是一種算法,數據結構里面有提到。在某一個地址上(對應一個哈希值,該值并不特指內存地址),存儲的是一個鏈表。在put一個新值時,根據該新值計算出哈希值,找到相應的位置,發現該位置已經蹲了一個,則新值就鏈接到舊值的下面,由舊值指向(next)它(也可能是倒過來指。。。)。可以參考HashMap)。
????這樣一來,當集合要添加新的元素時,先調用這個元素的hashCode方法,就一下子能定位到它應該放置的物理位置上。如果這個位置上沒有元素,它就可以直接存儲在這個位置上,不用再進行任何比較了;如果這個位置上已經有元素了,就調用它的equals方法與新元素進行比較,相同的話就不存了,不相同就散列其它的地址。所以這里存在一個沖突解決的問題。這樣一來實際調用equals方法的次數就大大降低了,幾乎只需要一兩次。
????所以,Java對于eqauls方法和hashCode方法是這樣規定的:
1、如果兩個對象相同,那么它們的hashCode值一定要相同;
2、如果兩個對象的hashCode相同,它們并不一定相同
????上面說的對象相同指的是用eqauls方法比較。
????你當然可以不按要求去做了,但你會發現,相同的對象可以出現在Set集合中。同時,增加新元素的效率會大大下降。

怎么重寫HashCode?

下面介紹如何來重寫hashCode()方法。通常重寫hashCode()方法按以下設計原則實現。

(1)把某個非零素數,例如17,保存在int型變量result中。

(2)對于對象中每一個關鍵域f(指equals方法中考慮的每一個域)參照以下原則處理。

boolean型,計算(f?0:1)。

byte、char和short型,計算(int)f。

long型,計算(int)(f^(f>>32))。

float型,計算Float.floatToIntBits(f)。

double型,計算Double.doubleToLongBits(f)得到一個long,再執行long型的處理。

對象引用,遞歸調用它的hashCode()方法。

數組域,對其中的每個元素調用它的hashCode()方法。

(3)將上面計算得到的散列碼保存到int型變量c,然后執行result = 37 * result + c。

(4)返回result。



類 HashMap<K,V>

java.lang.Objectjava.util.AbstractMap<K,V>?????java.util.HashMap<K,V>

  • 類型參數:

  • K?- 此映射所維護的鍵的類型

  • V?- 所映射值的類型

  • 基于哈希表的?Map?接口的實現。此實現提供所有可選的映射操作,并允許使用?null?值和null?鍵。(除了非同步和允許使用 null 之外,HashMap?類與?Hashtable?大致相同。)此類不保證映射的順序,特別是它不保證該順序恒久不變。

HashCode和HashMap之間的關系

先如下代碼:

import?java.util.HashMap;??
public?class?Test?{??//重寫Equals不重寫HashCode??static?class?Key?{??private?Integer?id;??private?String?value;??public?Key(Integer?id,?String?value)?{??super();??this.id?=?id;??this.value?=?value;??}??@Override??public?boolean?equals(Object?o)?{??if(o?==?null?||?!(o?instanceof?Key))?{??return?false;??}else?{??return?this.id.equals(((Key)o).id);??}??}??}??//重寫Equals也重寫HashCode??static?class?Key_?{??private?Integer?id;??private?String?value;??public?Key_(Integer?id,?String?value)?{??super();??this.id?=?id;??this.value?=?value;??}??@Override??public?boolean?equals(Object?o)?{??if(o?==?null?||?!(o?instanceof?Key_))?{??return?false;??}else?{??return?this.id.equals(((Key_)o).id);??}??}??@Override??public?int?hashCode()?{??return?id.hashCode();??}??}??public?static?void?main(String[]?args)?{??//test?hashcode??HashMap<Object,?String>?values?=?new?HashMap<Object,?String>(5);??Test.Key?key1?=???new?Test.Key(1,?"one");??Test.Key?key2?=???new?Test.Key(1,?"one");??System.out.println(key1.equals(key2));??values.put(key1,?"value?1");??System.out.println(values.get(key2));??Test.Key_?key_1?=???new?Test.Key_(1,?"one");??Test.Key_?key_2?=???new?Test.Key_(1,?"one");??System.out.println(key_1.equals(key_2));??System.out.println(key_1?==?key_2);??values.put(key_1,?"value?1");??System.out.println(values.get(key_2));??}??
}

輸出如下:由上述例子可見:只重寫了equasl方法的Key類 在用做Hash中的鍵值的時候 兩個equasl為true的對象不能獲取相應 的Value的而重寫了hashCode方法和equals方法的key_類 兩個相等的對象 可以獲取同一個Value的,這樣更符合生活中 的邏輯HashMap對象是根據Key的hashCode來獲取對應的Vlaue 因而兩個HashCode相同的對象可以獲取同一個Value

<span?style="color:#cc66cc;">??
</span>


轉載于:https://my.oschina.net/yongqingfan/blog/628174

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/285551.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/285551.shtml
英文地址,請注明出處:http://en.pswp.cn/news/285551.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

在OpenCloudOS使用snap安裝.NET 6

開源操作系統社區 OpenCloudOS 由騰訊與合作伙伴共同倡議發起&#xff0c;是完全中立、全面開放、安全穩定、高性能的操作系統及生態。OpenCloudOS 沉淀了多家廠商在軟件和開源生態的優勢&#xff0c;繼承了騰訊在操作系統和內核層面超過10年的技術積累&#xff0c;在云原生、穩…

C語言試題108之打印出所有的“水仙花數”,所謂“水仙花數”是指一個三位數,其各位數字立方和等于該數 本身。例如:153 是一個“水仙花數”,因為 153=1 的三次方+5 的三次方+3 的三次方。

?作者簡介:大家好我是碼莎拉蒂,CSDN博客專家?????? ??個人主頁:個人主頁 ??系列專欄:C語言試題200例 ??推薦一款模擬面試、刷題神器?? 點擊跳轉進入網站 1、題目 題目:打印出所有的“水仙花數”,所謂“水仙花數”是指一個三位數,其各位數字立方和等于該…

code vs1517 求一次函數解析式(數論 純數學知識)

1517 求一次函數解析式 時間限制: 1 s空間限制: 128000 KB題目等級 : 白銀 Silver題解查看運行結果題目描述 Description相信大家都做過練習冊上的這種 題吧&#xff1a; 已知一個一次函數的圖像經過點&#xff08;x1,y1&#xff09;、&#xff08;x2,y2&#xff09;,求該函數的…

【ArcGIS風暴】ArcGIS Editor for OSM中文教程(1):軟件下載及安裝

OpenStreetMap ArcGIS編輯器允許你使用ArcGIS工具為OpenStreetMap數據工作。這個桌面工具允許你加載OpenStreetMap數據并將其存儲在地理數據庫中 。你可以使用ArcMap熟悉的編輯環境的創建,修改,做網絡分析,或者更新數據。一旦您完成編輯后,你可以回到編輯修改OSM使它們提供…

使用Scrapy時出現雖然隊列里有很多Request但是卻不下載,造成假死狀態

2019獨角獸企業重金招聘Python工程師標準>>> DOWNLOAD_TIMEOUT Default: 180 The amount of time (in secs) that the downloader will wait before timing out. Note This timeout can be set per spider using download_timeoutspider attribute and per-request …

[轉]maven與java命名規則

MAVEN 與 JAVA 包命名規范 拋出問題 在使用MAVEN搭建模塊化項目時&#xff0c;我的組織結構如下&#xff1a; root模塊 文件夾名&#xff1a;package-module-project pom.xml文件&#xff1a; <project><groupId>com.chuillusion</groupId><artifactId>…

為什么 Istio 要使用 SPIRE 做身份認證?

今年 6 月初&#xff0c;Istio 1.14 發布 [1] &#xff0c;該版本中最值得關注的特性是新增對 SPIRE 的支持。SPIFFE[2] 和 SPIRE 都是 CNCF 孵化項目&#xff0c;其中 SPIRE 是 SPIFFE 的實現之一。本文將帶你了解 SPIRE 對于零信任架構的意義&#xff0c;以及 Istio 是為何使…

C語言試題106之有一對兔子,從出生后第 3 個月起每個月都生一對兔子,小兔子長到第三個月 后每個月又生一對兔子,假如兔子都不死,問每個月的兔子總數為多少?

1、題目 題目:有一對兔子,從出生后第 3 個月起每個月都生一對兔子,小兔子長到第三個月 后每個月又生一對兔子,假如兔子都不死,問每個月的兔子總數為多少? 分析:兔子的規律為數列 1,1,2,3,5,8,13,21… 2 、溫馨提示 想獲取更多C語言題目請猛搓這里==========》200個C語言…

顯式強制類型轉換

1. 日期顯式轉換為數字new Date; //1478845373322javascript有個奇特的語法&#xff0c;即構造函數沒有參數時可以不用帶()。不過最好還是使用ES5中新加入的靜態方法&#xff1a;Date.now()。2. ~運算符按位運算符只適用于32位整數&#xff0c;運算符會強制操作數使用32位格式。…

【ArcGIS風暴】ArcGIS Editor for OSM中文教程(2):下載及加載OSM數據

本文講解在ArcGIS中借助OpenStreetMap工具下載并加載OSM數據。 文章目錄 1. 下載OSM數據2. 加載OSM數據1. 下載OSM數據 在工具箱中雙擊Download OSM Data(XAPI)工具。 Download URL:http://www.overpass-api.de/api/xapi_meta? Downlaod Extent:與圖層lanzhou相同

Object.observe將不加入到ES7

先請看 Object.observe 的 API Object.observe(obj, callback[, acceptList])它用來監聽對象的變化&#xff0c;當給該對象添加屬性&#xff0c;修改屬性時都會被依次記錄下來 看一個示例 var person {} Object.observe(person, function(arr) {var change arr[0]console.log…

Kafka學習征途:.NET Core操作Kafka

【Kafka】| 總結/Edison Zhou1可用的Kafka .NET客戶端作為一個.NET Developer&#xff0c;自然想要在.NET項目中集成Kafka實現發布訂閱功能。那么&#xff0c;目前可用的Kafka客戶端有哪些呢&#xff1f;目前.NET圈子主流使用的是 Confluent.Kafkaconfluent-kafka-dotnet : htt…

C語言試題107之判斷 101至200 之間有多少個素數,并輸出所有素數。

?作者簡介:大家好我是碼莎拉蒂,CSDN博客專家?????? ??個人主頁:個人主頁 ??系列專欄:C語言試題200例 ??推薦一款模擬面試、刷題神器?? 點擊跳轉進入網站 1、題目 題目:判斷 101至200 之間有多少個素數,并輸出所有素數 分析:判斷素數的方法:用一個數分…

C語言將十進制輸出二進制、八進制、十六進制的方法總結

文章目錄 方法一:直接輸出方法二:itoa函數方法一:直接輸出 C語言中,控制printf函數輸出格式的是格式字符,printf沒有直接打出2進制數的格式符,直接打出16進制的格式符是x格式符,即%x。 printf函數中輸出的格式為printf("<格式化字符串>", <參量表&…

[Android] 修改ImageView的圖片顏色

有兩種方法&#xff1a; 方法1&#xff1a; ImageView imageView (ImageView) findViewById(R.id.arrow_image); Drawable tipsArrow imageView.getDrawable(); tipsArrow.setColorFilter(mContext.getResources().getColor(R.color.red_bg1), PorterDuf…

四叉樹算法

2019獨角獸企業重金招聘Python工程師標準>>> title: 四叉樹算法 date: 2016-1-11 15:10 categories: IOS tags: 算法 小小程序猿我的博客&#xff1a;http://daycoding.com 轉載&#xff1a;http://blog.csdn.net/zhanxinhang/article/details/6706217 高德iOS聚合…

2019年中國教育信息化行業研究報告

2019年中國教育信息化行業研究報告 教育行業丨研究報告 本文轉自&#xff1a;艾瑞咨詢 核心摘要&#xff1a; 教育信息化2.0時代&#xff0c;教育相關政府/學校以更開放的姿態對待社會各類業態的進入&#xff0c;共建共享優質教育資源&#xff0c;提升教育公平與教育質量。同…

C語言試題109之將一個正整數分解質因數。例如:輸入 90,打印出 90=2乘3乘3乘5

?作者簡介:大家好我是碼莎拉蒂,CSDN博客專家?????? ??個人主頁:個人主頁 ??系列專欄:C語言試題200例 ??推薦一款模擬面試、刷題神器?? 點擊跳轉進入網站 1、題目 題目:將一個正整數分解質因數。例如:輸入 90,打印出 90=233*5。 分析:對 n 進行分解質因…

【ArcGIS遇上Python】使用add-in向導開發ArcGIS插件(1):add-in工具介紹及安裝

文章目錄 addin介紹addin開發方式Python Add-In開發addin下載addin安裝基于ArcObject/ArcGIS Engine的Add-In開發addin介紹 ArcGIS從10.0開始支持addin(ArcGIS軟件中又叫作加載項)的方式進行插件制作。相對于以往9.x系列,addin的無論是從使用或者編寫都更加方便快捷。通過開…

dotnet 使用 Crossgen2 對 DLL 進行 ReadyToRun 提升啟動性能

我對幾個應用進行嚴格的啟動性能評估&#xff0c;對比了在 .NET Framework 和 dotnet 6 下的應用啟動性能&#xff0c;非常符合預期的可以看到&#xff0c;在用戶的設備上&#xff0c;經過了 NGen 之后的 .NET Framework 可以提供非常優越的啟動性能&#xff0c;再加上 .NET Fr…