java map中相同的key保存多個value值方式
map中相同的key保存多個value值
在java中,Map集合中隻能保存一個相同的key,如果再添加相同的key,則之後添加的key的值會覆蓋之前key對應的值,Map中一個key隻存在唯一的值。
如下代碼
package test; import org.junit.Test; import java.util.HashMap; import java.util.IdentityHashMap; import java.util.Map; import static java.util.Objects.hash; public class HashMapTest { @Test public void test0() { String str1 = new String("key"); String str2 = new String("key"); System.out.println(str1 == str2); Map<String,String> map = new HashMap<String,String>(); map.put(str1,"value1"); map.put(str2,"value2");//會覆蓋之前的值,map長度為1 /** * map比較鍵是否相同時是根據hashCode()和equals()兩個方法進行比較 * 先比較hashCode()是否相等,再比較equals()是否相等(實際上就是比較對象是否相等),如果都相等則認定是同一個鍵 */ for(Map.Entry<String,String> entry:map.entrySet()){ System.out.println(entry.getKey()+" "+entry.getValue()); } System.out.println("------->"+map.get("key")); } 控制臺輸出如下: /** * 以上代碼可以看出普通的map集合相同的key隻能保存一個value * 但是有一個特殊的map--->IdentityHashMap可以實現一個key保存多個value * 註意:此類並不是通用的Map實現!此類再實現Map接口的時候違反瞭Map的常規協定,Map的常規協議在 * 比較對象強制使用瞭equals()方法,但此類設計僅用於其中需要引用相等性語義的情況 * (IdentityhashMap類利用哈希表實現Map接口,比較鍵(和值)時使用引用相等性代替對象相等性, * 也就是說做key(value)比較的時候隻比較兩個key是否引用同一個對象) */ @Test public void test1(){ String str1 = "key"; String str2 = "key"; System.out.println(str1 == str2); Map<String,String> map = new IdentityHashMap<>(); map.put(str1,"value1"); map.put(str2,"value2"); for(Map.Entry<String,String> entry:map.entrySet()){ System.out.println(entry.getKey()+" "+entry.getValue()); } System.out.println("containsKey---->"+map.get("key")); System.out.println("value---->"+map.get("key")); } 控制臺輸出如下 /** * test1中的IdentityHashMap中的key為“key”還是隻保存瞭一個值,以為“key”在內存中隻存在一個對象, * 而str1與str2對對"key"字符串的引用是相等的,所以添加的時候就發生瞭覆蓋 */ @Test public void test2(){ String str1 = new String("key"); String str2 = new String("key"); System.out.println(str1 == str2); Map<String, String> map = new IdentityHashMap<>(); map.put(str1,"value1"); map.put(str2,"value2"); for(Map.Entry<String,String> entry:map.entrySet()){ System.out.println(entry.getKey()+" "+entry.getValue()); } System.out.println("\"key\" containKey--->"+map.containsKey("key")); System.out.println("str1 containKey--->"+map.containsKey(str1)); System.out.println("str2 containKey--->"+map.containsKey(str2)); System.out.println("value--->"+map.get("key")); System.out.println("value--->"+map.get(str1)); System.out.println("value--->"+map.get(str2)); } 控制臺輸出如下: /** * test2中str1,str2都在內存中指向不同的String對象,他們的哈希值是不同的,所以在identityHashMap中可以的比較 * 中會認為不同的key,所以會存在相同的“key”值對應不同的value值 */ /** * 既然提到瞭map的key的比較,再說一下map中實現自定義類做key值時應該註意的一些細節, * 在HashMap中對於key的比較時通過兩步完成的 * 第一步:計算對象的hash Code的值,比較是否相等 * 第二步: 檢查對應的hash code對應位置的對象是否相等 * 在第一步中會調用到對象中的hashCode()方法,第二步中會調用的對象中的equals()方法 * * 所以想要實現自定義對象作為Map的key值,保證key值的唯一性,需要在子定義對象中重寫以上兩個方法,如以下對象: */ private class CustomObject{ private String value; public CustomObject(String value){ this.value = value; } public String getValue() { return value; } public void setValue(String value) { this.value = value; } /** * 省略自定義的一些屬性方法 * ...... */ @Override public int hashCode() { if(value !=null){ return super.hashCode()+hash(value); }else{ return super.hashCode(); } } @Override public boolean equals(Object obj) { if(this == obj){ return true; } if(obj == null || getClass() != obj.getClass()){ return false; } CustomObject object = (CustomObject) obj; if(this.value != null && this.value.equals(object.getValue())){ return true; } if(this.value == null && object.value == null){ return true; } return false; } } }
Map中相同的鍵Key不同的值Value實現原理
Map中相同的鍵Key對應不同的值Value通常出現在樹形結構的數據處理中,通常的實現方法有JDK提供的IdentityHashMap和Spring提供的MultiValueMap。
public static void main(String[] args) { Map<String, Object> identity = new IdentityHashMap<>(); identity.put("A", "A"); identity.put("A", "B"); identity.put("A", "C"); Map<String, Object> identityString = new IdentityHashMap<>(); identityString.put(String.join("A", ""), "B"); identityString.put("A", "A"); identityString.put(new String("A"), "C"); MultiValueMap<String, Object> linked = new LinkedMultiValueMap<>(); linked.add("A", "A"); linked.add("A", "B"); linked.add("A", "C"); for (String key : identity.keySet()) { System.out.println("identity:" + identity.get(key)); } for (String key : identityString.keySet()) { System.out.println("identity string:" + identityString.get(key)); } for (String key : linked.keySet()) { System.out.println("linked:" + linked.get(key)); } }
實現原理
- JDK提供的IdentityHashMap其底層是根據Key的hash碼的不同+transient Object[] table來實現的;
- Spring提供的LinkedMultiValueMap其底層是使用LinkedHashMap來實現的;
- LinkedHashMap的底層是使用transient Entry<K, V> head和transient Entry<K, V> tail來實現的;
- Entry是LinkedHashMap的內部類,其定義方式為:
static class Entry<K, V> extends HashMap.Node<K, V> { Entry<K, V> before; Entry<K, V> after; }
總結
IdentityHashMap和LinkedMultiValueMap的實現歸根結底就是數組和鏈表的使用。
以上為個人經驗,希望能給大傢一個參考,也希望大傢多多支持WalkonNet。
推薦閱讀:
- 在Map中實現key唯一不重復操作
- Java中Map接口使用以及有關集合的面試知識點匯總
- Java Map.entry案例詳解
- 為何修改equals方法時還要重寫hashcode方法的原因分析
- 搞懂JAVAObject中的hashCode()