java map中相同的key保存多个value值方式
更新时间:2021年8月29日 00:00 点击:1412
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的实现归根结底就是数组和链表的使用。
以上为个人经验,希望能给大家一个参考,也希望大家多多支持猪先飞。
上一篇: 在Map中实现key唯一不重复操作
下一篇: 详细图解Java中字符串的初始化
相关文章
- 这篇文章主要介绍了如何利用java语言实现经典《复杂迷宫》游戏,文中采用了swing技术进行了界面化处理,感兴趣的小伙伴可以动手试一试...2022-02-01
Java8 实现stream将对象集合list中抽取属性集合转化为map或list
这篇文章主要介绍了Java8 实现stream将对象集合list中抽取属性集合转化为map或list的操作,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2021-02-05java 运行报错has been compiled by a more recent version of the Java Runtime
java 运行报错has been compiled by a more recent version of the Java Runtime (class file version 54.0)...2021-04-01- 这篇文章主要介绍了在java中获取List集合中最大的日期时间操作,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2020-08-15
- 这篇文章主要介绍了@CacheEvict 清除多个key的实现方式,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2021-02-13
- 这篇文章主要介绍了教你怎么用Java获取国家法定节假日,文中有非常详细的代码示例,对正在学习java的小伙伴们有非常好的帮助,需要的朋友可以参考下...2021-04-23
- 这篇文章主要介绍了Java如何发起http请求的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2021-03-31
- 说起C#和Java这两门语言(语法,数据类型 等),个人以为,大概有90%以上的相似,甚至可以认为几乎一样。但是在工作中,我也发现了一些细微的差别...2020-06-25
- 这篇文章主要介绍了解决Java处理HTTP请求超时的问题,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2021-03-29
- 下面小编就为大家带来一篇js遍历json的key和value的实例。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧...2017-01-26
- 这篇文章主要介绍了@Cacheable 拼接key的操作,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2021-02-13
- 这篇文章主要介绍了浅谈redis key值内存消耗以及性能影响,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2021-02-07
- 这篇文章主要介绍了java 判断两个时间段是否重叠的案例,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2020-08-15
- 这篇文章主要介绍了uniapp微信小程序:key失效的解决方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2021-01-20
- 这篇文章主要介绍了超简洁java实现双色球若干注随机号码生成(实例代码),本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下...2021-04-02
- 这篇文章主要介绍了Java生成随机姓名、性别和年龄的实现示例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2020-10-01
java 画pdf用itext调整表格宽度、自定义各个列宽的方法
这篇文章主要介绍了java 画pdf用itext调整表格宽度、自定义各个列宽的方法,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2021-01-31- 这篇文章主要介绍了java正则表达式判断前端参数修改表中另一个字段的值,需要的朋友可以参考下...2021-05-07
Java使用ScriptEngine动态执行代码(附Java几种动态执行代码比较)
这篇文章主要介绍了Java使用ScriptEngine动态执行代码,并且分享Java几种动态执行代码比较,需要的朋友可以参考下...2021-04-15JavaScript中的数组遍历forEach()与map()方法以及兼容写法介绍
下面小编就为大家带来一篇JavaScript中的数组遍历forEach()与map()方法以及兼容写法介绍。小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧...2016-05-20