java map中相同的key保存多个value值方式
程序员文章站
2022-03-29 23:09:11
目录map中相同的键key不同的值value实现原理map中相同的key保存多个value值在java中,map集合中只能保存一个相同的key,如果再添加相同的key,则之后添加的key的值会覆盖之前...
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的实现归根结底就是数组和链表的使用。
以上为个人经验,希望能给大家一个参考,也希望大家多多支持。
下一篇: 你开美颜了吗