一個簡單需求:HashMap實現相同key存入數據后不被覆蓋


做一個積極的人

編碼、改bug、提升自己

我有一個樂園,面向編程,春暖花開!

看似是一個簡單的問題,其實里面包含很多的東西!

需求

實現一個在HashMap中存入(任意類型)相同的key值后,key中的value不會被覆蓋,而是能夠進行疊加!

拿到一個需求的時候,我們要先進行分析,看此需求能否實現,基於已有的知識(經驗),然后在通過目前的一些技術看此需求如何實現。

要實現在HashMap中插入相同的key值,內容不被覆蓋,那么肯定要了解HashMap的一些機制,首先看一下HashMap的put方法:

從JDK API中看到HashMap的put如何先前存儲了一個key(鍵),在指定相同的key(鍵)的時候,會用新的值替換舊的值。

如下的代碼示例:

public static void main(String[] args) { Map<String, Object> map = new HashMap<>(); map.put("aflyun", "Java編程技術樂園"); map.put("aflyun", "生活在長沙的延安人"); System.out.println(map.toString()); } --打印:-- {aflyun=生活在長沙的延安人} 

通過上面的示例分析:為什么存入相同的key后,舊值就被新值替換了呢?

要想知道具體原因,那只能去看HashMap的源碼實現了。看一下put(K key, V value)方法了,本篇HashMap源碼是JDK1.8版本!

/** * HashMap 的put方法 **/ public V put(K key, V value) { return putVal(hash(key), key, value, false, true); } /** * HashMap 的containsKey方法 **/ public boolean containsKey(Object key) { return getNode(hash(key), key) != null; } /** * 將存入的key進行hash操作,也就是使用key.hashCode()! **/ static final int hash(Object key) { int h; return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16); } 

判斷put和判斷key是否是同一個key的時候,使用大概如下判斷邏輯:

if (e.hash == hash && ((k = e.key) == key || (key != null && key.equals(k)))) 

先判斷Hash是否一致,然后在判斷傳入key和當前集合中是否有相同的key。如果key相同,則新值替換舊值。其中在判斷中使用了

  • ==
  • equals

==和 equals 的區別有時候面試會問到,如何你知道這兩個的區別不僅看源碼能夠很好的理解,並且遇到面試也不怕了。


tips:簡述==和 equals 的區別>

 1)對於==,如果作用於基本數據類型的變量,則直接比較其存儲的 “值”是否相等;如果作用於引用類型的變量,則比較的是所指向的對象的地址!

 2)對於equals方法,注意:equals方法不能作用於基本數據類型的變量。如果沒有對equals方法進行重寫,則比較的是引用類型的變量所指向的對象的地址;諸如String等類對equals方法進行了重寫的話,比較的是所指向的對象的內容。


有了上面的分析基礎,那針對上面String類型的key的話,那實現起來就比較簡單了!因為String中已經實現了HashCode和 equals代碼如下:

  • 自定義HashMap
public class MyHashMap<K> extends HashMap<K,String> { /** * 使用HashMap中containsKey判斷key是否已經存在 * @param key * @param value * @return */ @Override public String put(K key, String value) { String newV = value; if (containsKey(key)) { String oldV = get(key); newV = oldV + "---" + newV; } return super.put(key, newV); } } 
  • String類型key的進行put操作
public static void main(String[] args) { MyHashMap<String> map = new MyHashMap<String>(); map.put("aflyun", "Java編程技術樂園"); map.put("aflyun", "生活在長沙的延安人"); map.put("aflyun", "期待你加入樂園"); System.out.println(map.toString()); } --打印:--- {aflyun=Java編程技術樂園---生活在長沙的延安人---期待你加入樂園} 

此時同樣的key內容是進行疊加的,不是進行替換!那如何是自定義的類,要當作key,那要怎么做呢?

其實也就是重寫了hashCode和equals就可以了。

public class PrettyGirl { /** * 姑娘唯一認證ID */ private String id; /** * 姑娘姓字名誰 */ private String name; @Override public boolean equals(Object o) { if (this == o) {return true;} if (o == null || getClass() != o.getClass()) {return false;} PrettyGirl that = (PrettyGirl) o; return Objects.equals(id, that.id) && Objects.equals(name, that.name); } @Override public int hashCode() { return Objects.hash(id, name); } } 
  • 自定義類型當做key的進行put操作
public static void main(String[] args) { PrettyGirl prettyGirl = new PrettyGirl(); Map<PrettyGirl,String> map = new HashMap<>(); map.put(prettyGirl, "Java編程技術樂園"); map.put(prettyGirl, "生活在長沙的延安人"); map.put(prettyGirl, "期待和你加入樂園"); System.out.println("map :" + map.toString()); MyHashMap<PrettyGirl> myMap = new MyHashMap<PrettyGirl>(); myMap.put(prettyGirl, "Java編程技術樂園"); myMap.put(prettyGirl, "生活在長沙的延安人"); myMap.put(prettyGirl, "期待和你加入樂園"); System.out.println("myMap :" + myMap.toString()); } --打印:--- map :{com.happy.PrettyGirl@3c1=期待和你加入樂園} myMap :{com.happy.PrettyGirl@3c1=Java編程技術樂園---生活在長沙的延安人---期待和你加入樂園} 

總結:要實現開頭的需求

1、如果是類似String這種,已經重寫了hashCode和equals的。則只需要創建一個自己的HashMap類,重寫put即可。

2、如果是自定義的類,那就必須重寫了hashCode和equals的,然后在使用自定義的HashMap類了。

具體的代碼判斷邏輯:

判斷key是否存在的時候是先比較key的hashCode,再比較相等或equals的,所以重寫hashCode()和equals()方法即可實現添加重復元素。重寫這兩個方法之后就可以覆蓋重復的鍵值對,如果需要對value進行疊加,調用put()方法之前用containsKey()方法判斷是否有重復的鍵值,如果有,則用get()方法獲取原有的value,再加上新加入的value即可。

本文涉及的相關知識:

1、HashMap相關源碼

2、== 、equals和 hashCode

3、Hash算法

相關面試題:

1、為什么要重寫了equals方法必須要重寫hashcode方法?

2、使用HashMap在什么情況會出現內存泄漏?


謝謝你的閱讀,如果您覺得這篇博文對你有幫助,請點贊或者喜歡,讓更多的人看到!祝你每天開心愉快!


 

不管做什么,只要堅持下去就會看到不一樣!在路上,不卑不亢!

願你我在人生的路上能都變成最好的自己,能夠成為一個獨擋一面的人

© 每天都在變得更好的阿飛雲


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM