java map中相同的key保存多个value值方式
作者:成都杨小天 发布时间:2022-12-12 20:05:45
标签: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的实现归根结底就是数组和链表的使用。
来源:https://blog.csdn.net/weixin_37774620/article/details/79128212


猜你喜欢
- Springmvc+hibernate成为现在很多人用的框架整合,最近自己也在学习摸索,由于我们在开发项目中很多项目都用到列表分页功能,在此
- 本文实例为大家分享了Android实现自动转圈效果展示的具体代码,供大家参考,具体内容如下在values文件夹下创建attrs.xml<
- @Autowired加到接口上但获取的是实现类问题Spring的@Autowired加到接口上但获取的是实现类? &
- 本文实例讲述了C#中IEnumerable接口用法。分享给大家供大家参考。具体分析如下:枚举数可用于读取集合中的数据,但不能用于修改基础集合
- 程序分析: 兔子的规律为数列1,1,2,3,5,8,13,21....程序设计:public class exp2{ publi
- HTTP 头处理HTTP 头是 HTTP 请求和响应中的重要组成部分。在创建 HTTP 请求时需要设置一些 HTTP 头。在得到 HTTP
- 这篇文章主要介绍了Spring如何使用注解的方式创建bean,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需
- 本文实例为大家分享了Android实现五子棋游戏的具体代码,供大家参考,具体内容如下直接上效果图原理从棋盘到棋子,到开始下棋的各类点击事件,
- 废话不多说了,直接步入正题了。1、批量添加元素session.insert(String string,Object o)public vo
- 前言app启动后的白屏问题,默认都是在splash页面加主题配置,主题配置一个背景来达到用户点击app图标就立马启动app的假象,大多情况下
- 本文所述为一个Android上传文件的源代码,每一步实现过程都备有详尽的注释,思路比较清楚,学习了本例所述上传文件代码之后,你可以应对其它格
- 一、问题定义:问下有一个数组,这些数组中的值都有自己的权重,怎样设计才能高效的优先取出权重高的数??例如:权重: 8 2&nbs
- 使用到的类:net.sf.json.JSONObject 使用JSON时,除了要导入JSON网站上面下载的json-lib-2.2
- 一、背景在Idea中有些文件无需与远程git库同步,仅是本地使用,比如*.iml 、.idea(文件夹)等。如果不进行设置,那么每次提交列表
- 异常与错误:异常: 在Java中程序的错误主要是语法错误和语义错误,一个程序在编译和运行时出现的错误我们统一称之为异常,它是VM(虚拟机)通
- 最近在做一个项目,需要用到非对称加密,但是出现一个很诡异的情况,本地开发环境是Windows环境,测试环境是Linux环境,出现一个问题,
- 本文以eclipse4.7安装sts3.9.0为例,解决报错An error occurred while collecting items
- 一、依赖注入(DI)依赖注入听起来很高深的样子,其实白话就是:给属性赋值。一共有两种方法,第一是以构造器参数的形式,另外一种就是以setti
- 高快省的排序算法有没有既不浪费空间又可以快一点的排序算法呢?那就是“快速排序”啦!光听这个名字是不是就觉得很高端呢。假设我们现在对“6 1
- 一.显示、隐藏 jQuery 中显示方法为:.show(),隐藏方法为:.hide()。在无参数的时候,只是硬性的显示内容和隐藏内