java map中相同的key保存多个value值方式

目录
  • 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的实现归根结底就是数组和链表的使用。

以上为个人经验,希望能给大家一个参考,也希望大家多多支持我们。

(0)

相关推荐

  • sql查询返回值使用map封装多个key和value实例

    直接上代码,代码是测试过的 1.重写ResultHandler public class MapResultHandler implements ResultHandler { private final Map mappedResults = new HashMap(); @Override public void handleResult(ResultContext context) { @SuppressWarnings("rawtypes") Map map = (Map) c

  • java8 Stream list to Map key 重复 value合并到Collectio的操作

    java8 Stream list to Map key 重复 value合并到Collectio 关于把list转换成key value的map有很多博客上都有实现,这里是一个把value放入到集合中去 List<String> list = Lists.newArrayList("1", "2", "3", "1"); Map<String, List<String>> map = li

  • HashMap实现保存两个key相同的数据

    HashMap如何保存两个key相同的数据 最近一个朋友去面试了,面试官问了一个关于HashMap的问题:HashMap如何保存两个key相同的数据? 准确来说,应该是Map中如何保存两个key相同的数据,因为用来实现这个功能的IdentityHashMap类和HashMap虽然都是实现了Map接口,但本质是属于不同的东西: 我们知道在HashMap中,如果key相同就会被覆盖,那IdentityHashMap是怎么实现这个功能的呢? java jdk源码中,IdentityHashMap类上写

  • Java 遍历取出Map集合key-value数据的4种方法

    将map集合存数据与取出数据全部放在一个类MapTest中,方便阅读与查看 随便创建一个包,在包中新建一个class文件,(也可以不建包,直接新建一个class文件) 新建class文件MapTest.java,代码如下: import java.util.HashMap; import java.util.Iterator; import java.util.Map; import java.util.Map.Entry; import java.util.Set; public class

  • java map中相同的key保存多个value值方式

    目录 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.Id

  • Java如何在Map中存放重复key

    目录 如何在Map中存放重复key 1.概述 2.将集合作为Value 3.使用Apache Commons Collections 4.Guava Multimap 5.自定义MultiMap Map出现重复Key值叠加到上一个key中 如何在Map中存放重复key 1.概述 本文介绍几种处理Map中一个key对多个value的方法.在JDK标准Map实现中当我们尝试在一个key下插入多个value,那么后续的value会覆盖前面的value. Map<String, String> map

  • MyBatis中foreach标签的collection属性的取值方式

    目录 foreach标签的collection属性的取值 传的是List列表 传的是Array数组 传的是Map collection属性总结 MyBatis使用foreach标签报错 原因 解决方案 foreach标签的collection属性的取值 传的是List列表 接口代码 List<Emp> findEmpByDeptnos(List<Integer> deptnos); xml配置代码 <select id="findEmpByDeptnos"

  • 在Map中实现key唯一不重复操作

    Map中如何实现key唯一不重复 问题:如何做到Map中key唯一不重复,每次都遍历来equals比较吗? 首先,答案是否.如果全部遍历的话,当Map中元素很多的时候,显然查询效率低. 解释: HashMap属于散列存储结构,其table的存储是放在不同的Jvm内存区域.通过一个整型值来标识table的区域,相当于这个区域的下标.然后整个查找过程就从不再需要遍历整个table,只需遍历这一区域的数据即可. 结合HashMap.class中的put方法来说明: 如何找到这个区域呢? 1.首先将传入

  • Java8 Map中新增的方法使用总结

    前言 得益于 Java 8 的 default 方法特性,Java 8 对 Map 增加了不少实用的默认方法,像 getOrDefault, forEach, replace, replaceAll, putIfAbsent, remove(key, value), computeIfPresent, computeIfAbsent, compute 和merge 方法.另外与 Map 相关的 Map.Entry 也新加了多个版本的 comparingByKey 和 comparingByVal

  • java Map接口子类HashMap遍历与LinkedHashMap详解

    目录 一.概述 二.Map常用子类 三.Map接口中的常用方法 四.Map集合遍历键找值方式 五.Entry键值对对象 六.Map集合遍历键值对方式 七.HashMap存储自定义类型键值 八.LinkedHashMap 九.Map集合练习 十.JDK9对集合添加的优化 一.概述 现实生活中,我们常会看到这样的一种集合:IP地址与主机名,身份证号与个人,系统用户名与系统用户对象等,这种一一对应的关系,就叫做映射.Java提供了专门的集合类用来存放这种对象关系的对象,即java.util.Map接口

  • Java多线程中线程间的通信实例详解

    Java多线程中线程间的通信 一.使用while方式来实现线程之间的通信 package com.ietree.multithread.sync; import java.util.ArrayList; import java.util.List; public class MyList { private volatile static List list = new ArrayList(); public void add() { list.add("apple"); } publ

  • Java实现将容器 Map中的内容保存到数组

    我就废话不多说了,大家还是直接看代码吧~ import java.util.Map; import java.util.HashMap; import java.util.Map.Entry; public class mapToArr { public static void main(String[] args) { Map<String, Integer> map = new HashMap<String, Integer>(); map.put( "a"

  • Java基础将Bean属性值放入Map中的实例

    Java基础将Bean属性值放入Map中的实例 利用发射将Java对象的属性值以属性名称为键,存储到Map中的简单实现.包括自身属性及从父类继承得到的属性.Java类型的getField[s]方法只能获取public 类型的属性,getDeclaredFields则能获取所有声明的属性,同时,如果类的可见性非公有,则Field的get(Object)方法将取不到具体的属性值. package com.wood.util; import java.lang.reflect.Field; impor

  • 如何在java 8 map中使用stream

    简介 Map是java中非常常用的一个集合类型,我们通常也需要去遍历Map去获取某些值,java 8引入了Stream的概念,那么我们怎么在Map中使用Stream呢? 基本概念 Map有key,value还有表示key,value整体的Entry. 创建一个Map: Map<String, String> someMap = new HashMap<>(); 获取Map的entrySet: Set<Map.Entry<String, String>> en

随机推荐