目录
map中雷同的key保留多个value值
如下代码
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的实现归根结底就是数组和链表的应用。

以上为集体教训,心愿能给大家一个参考