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

作者:成都杨小天 时间:2022-12-12 20:05:45 

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

来源:https://blog.csdn.net/weixin_37774620/article/details/79128212

标签:java,map,key,value值
0
投稿

猜你喜欢

  • MyBatis学习教程(五)-实现关联表查询方法详解

    2021-06-23 21:04:04
  • C#实现GridView导出Excel实例代码

    2023-10-29 04:31:09
  • 使用OkHttp包在Android中进行HTTP头处理的教程

    2023-06-16 23:55:37
  • APK程序获取system权限的方法

    2023-09-05 06:41:49
  • Java实现添加文字水印&图片水印的方法详解

    2023-01-28 08:11:39
  • JAVA版排序算法之快速排序示例

    2023-04-20 04:37:53
  • 一篇文章弄懂Java8中的时间处理

    2022-07-22 07:56:32
  • Java线程同步方法实例总结

    2022-08-20 20:35:08
  • 轻松学习C#的装箱与拆箱

    2021-07-01 12:11:51
  • Mapreduce分布式并行编程

    2023-04-30 02:43:16
  • Java实现解出世界最难九宫格问题

    2022-06-14 19:47:10
  • 实现一个Android锁屏App功能的难点总结

    2022-07-21 03:03:19
  • C# Double转化为String时的保留位数及格式方式

    2021-09-08 13:12:00
  • 基于OpenGL实现多段Bezier曲线拼接

    2022-03-07 03:47:31
  • java list,set,map,数组间的相互转换详解

    2023-04-11 13:02:04
  • 避免sql注入_动力节点Java学院整理

    2023-08-21 17:39:12
  • 详解Java如何在CompletableFuture中实现日志记录

    2022-03-21 17:11:01
  • C#将Sql数据保存到Excel文件中的方法

    2023-11-11 08:34:26
  • 深入学习java枚举的应用

    2022-10-27 19:56:34
  • SpringCloud基本Rest微服务工程搭建过程

    2023-08-28 16:23:29
  • asp之家 软件编程 m.aspxhome.com