詳談Map的key、value值的數(shù)據(jù)類型不能為基本類型的原因
interface Map<K,V>
Map源碼
/** * Returns the hash code value for this map entry. The hash code * of a map entry <tt>e</tt> is defined to be: <pre> * (e.getKey()==null ? 0 : e.getKey().hashCode()) ^ * (e.getValue()==null ? 0 : e.getValue().hashCode()) * </pre> * This ensures that <tt>e1.equals(e2)</tt> implies that * <tt>e1.hashCode()==e2.hashCode()</tt> for any two Entries * <tt>e1</tt> and <tt>e2</tt>, as required by the general * contract of <tt>Object.hashCode</tt>. * * @return the hash code value for this map entry * @see Object#hashCode() * @see Object#equals(Object) * @see #equals(Object) */ int hashCode();
hashCode返回 (e.getKey()==null ? 0 : e.getKey().hashCode()) ^(e.getValue()==null ? 0 : e.getValue().hashCode())
class HashMap<K,V> extends AbstractMap<K,V> implements Map<K,V>, Cloneable, Serializable
HashMap源碼中:
public final int hashCode() { return Objects.hashCode(key) ^ Objects.hashCode(value); }
static final int hash(Object key) { int h; return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16); }
public final boolean equals(Object o) { if (o == this) return true; if (o instanceof Map.Entry) { Map.Entry<?,?> e = (Map.Entry<?,?>)o; if (Objects.equals(key, e.getKey()) && Objects.equals(value, e.getValue())) return true; } return false; }
補(bǔ)充知識:java hashmap key long 和int 區(qū)別
最近同事問起,map里面存的key 是int 類型的,存了一個(gè) Integera =123,為什么使用long 123 作為key get,取出來的是空,這個(gè)問題粗想了一下,感覺long和int 本身 類型不同,肯定不能是同一個(gè)key,后來細(xì)研究了一下,跟了一下源碼,發(fā)現(xiàn)邏輯不是那么簡單。
簡單測試了一下,如下代碼
Map<Object,String> map = new HashMap<>(); Integer b = 123; Long c =123L; map.put(b, b+"int"); System.out.println(b.hashCode() == c.hashCode()); //true System.out.println(map.get(c)); //null map.put(c, c+"long"); // size =2
簡單的總結(jié)了一下問題:
1、HashMap 是把key做hash 然后作為數(shù)組下標(biāo),但是 b 和c 的hashcode 竟然是相同的,為什么 get(c) 為空
2、HashMap 存入c 發(fā)現(xiàn) size=2 ,hashcode相同 為什么 size=2,get(c) =123long
帶著上面兩個(gè)問題跟了一遍源碼,問題豁然開朗
1、hashmap在存入的時(shí)候,先對key 做一遍 hash,以hash值作為數(shù)組下標(biāo),如果發(fā)現(xiàn) 下標(biāo)已有值,判斷 存的key 跟傳入的key是不是相同,使用 (k = p.key) == key || (key != null && key.equals(k)) ,如果相同覆蓋,而Interger的equals 方法如下:
if (obj instanceof Integer) { return value == ((Integer)obj).intValue(); } return false;
Integer 和 Long 肯定不是一個(gè)類型,返回 false,這時(shí)候 hashmap 以 hashkey 沖突來處理,存入鏈表,所以 Long 123 和 Integer 123 hashmap會(huì)認(rèn)為是 hash沖突
2、hashmap 在 get的時(shí)候,也是先做 hash處理,根據(jù)hash值查找對應(yīng)的數(shù)組下標(biāo),如果找到,使用存入時(shí)候的判斷條件
(k = first.key) == key || (key != null && key.equals(k)) 如果相等就返回,不相等,查找當(dāng)前值的next有沒有值,有繼續(xù)根據(jù)邏輯判斷,所以 存入Integer 123 根據(jù) Long 123 來獲取返回的 是 NULL
至此,解析完畢。
以上這篇詳談Map的key、value值的數(shù)據(jù)類型不能為基本類型的原因就是小編分享給大家的全部內(nèi)容了,希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
使用IDEA進(jìn)行安卓開發(fā)的詳細(xì)圖文教程
安卓開發(fā)本身就是Java開發(fā)的一個(gè)分支,我們要確保計(jì)算機(jī)已經(jīng)安裝好JDK并做好了相關(guān)的配置,下面這篇文章主要給大家介紹了關(guān)于如何使用IDEA進(jìn)行安卓開發(fā)的詳細(xì)圖文教程,需要的朋友可以參考下2023-04-04SPRINGBOOT讀取PROPERTIES配置文件數(shù)據(jù)過程詳解
這篇文章主要介紹了SPRINGBOOT讀取PROPERTIES配置文件數(shù)據(jù)過程詳解,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2019-12-12Mybatis核心配置文件、默認(rèn)類型別名、Mybatis獲取參數(shù)值的兩種方式(實(shí)例代碼)
這篇文章主要介紹了Mybatis核心配置文件、默認(rèn)類型別名、Mybatis獲取參數(shù)值的兩種方式,本文通過實(shí)例代碼給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友參考下吧2024-03-03vscode快速引入第三方j(luò)ar包發(fā)QQ郵件
這篇文章主要介紹了vscode快速引入第三方j(luò)ar包發(fā)QQ郵件,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-06-06SpringBoot整合Mybatis與druid實(shí)現(xiàn)流程詳解
這篇文章主要介紹了springboot整合mybatis plus與druid詳情,文章圍繞主題展開詳細(xì)的內(nèi)容介紹,具有一定的參考價(jià)值,需要的下伙伴可以參考一下2022-10-10一文了解Java動(dòng)態(tài)代理的原理及實(shí)現(xiàn)
動(dòng)態(tài)代理指的是,代理類和目標(biāo)類的關(guān)系在程序運(yùn)行的時(shí)候確定的,客戶通過代理類來調(diào)用目標(biāo)對象的方法,是在程序運(yùn)行時(shí)根據(jù)需要?jiǎng)討B(tài)的創(chuàng)建目標(biāo)類的代理對象。本文將通過案例詳細(xì)講解一下Java動(dòng)態(tài)代理的原理及實(shí)現(xiàn),需要的可以參考一下2022-07-07如何將Spring Session存儲(chǔ)到Redis中實(shí)現(xiàn)持久化
這篇文章主要介紹了如何將Spring Session存儲(chǔ)到Redis中實(shí)現(xiàn)持久化,本文通過實(shí)例代碼給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2023-07-07