Map集合的概念:
interface Map<key,value>
和前面学习的List和Set集合不同,他是有两个泛型一个key、一个value、有key映射value,并且key不允许重复。
key和value的关系就好比是学号和学生的关系。
map集合添加方法是put这个不能和前面的List和Set的搞混。
Map<String,String> map=new HashMap<>();
map.put("001","ww");
map.put("002","qqq");
map.put("002","ppp");
System.out.println(map);
这里输出结果:
001=ww
002=ppp
你会发现第二个002将第一个002覆盖掉了。
大概原理:比较他们之间的key,如果发现一致就比较他们的value,发现value不同就执行put将前面那个value覆盖。如果发现value也是一样时就不会执行覆盖。
重点方法:
V get(Object key):通过键获取值
Set<K> KeySet();获取所有键的集合
Collection<V> values();获取所有值的集合
Set<Map.Entry<K,V>> entrySet() ;获取所有键值对的集合
代码1:
Map<String,String> map=new HashMap<>();
map.put("001","ww");
map.put("002","qqq");
map.get("001");//有就得到value,没有就输出null
Set<String> keys=map.keySet();//获取所有的key
for(String key:keys){
System.out.println(key);
}
Collection<String> values=map.values();//获取所有的value
for(String value:values){
System.out.println(value);
}
代码2(键-->值):
Map<String,String> map=new HashMap<>();
map.put("001","ww");
map.put("002","qqq");
Set<String> keys=map.keySet();
for(String key:keys){
String value=map.get(key);
System.out.println(key+"="+value);
}
代码3(key<-----键值对集合----->value):相当于通过结婚证直接获取丈夫和妻子
Map<String,String> map=new HashMap<>();
map.put("001","ww");
map.put("002","qqq");
Set<Map.Entry<String,String>> sets=map.entrySet();//获取所有的键值对集合
for(Map.Entry<String,String> map:sets){
sets.getKey();//获取值
sets.getvalue();//获取值
}
特别提醒:key的唯一性也是通过哈希表实现的,所以key存储是对象时,我们要在对象里面重写equals和HashCode方法。
HashMap:
1、允许只有一个key为空,一个或多个value为null
2、线程不安全
3、底层:链表+数组:当阈值大于8时转为 红黑树+数组
4、默认初始化大小为16、之后每次扩容*2,如果指定大小时HashMap会扩充为2的幂次方大小(减少碰撞)。
概念及底层原理:底层是链表加数组、这里key的查重原理和上面的Map接口说的是一样的。HashMap通过key的hashCode经过扰动函数处理后得到hash值、通过(n-1)&hash,n为数组长度n-1就是对应数组里面的位置了。如果在该数组位置发现有元素,就在用要添加的元素于该存在存在元素进行比较hash值和key值、如果两个相同直接覆盖、如果不相同就,使用到底层的拉链法进行冲突解决(红黑树/链表);
对于HashMap多线程操作导致死循环问题:
主要原因在于并发的Rehash会造成元素之间形成一个循环链表、不过jdk1.8后解决了这个问题、但是还是不建议在多线程下使用、因为在多线程下使用HashMap还是会存在数据丢失这类问题的存在,并发环境下建议使用ConcurrentHashMap。
这里大部分时候我们会用HashMap和HashSet做比较
HashMap:实现了Map接口、存储的是键值对、添加方法是put、HashMap使用键(key)计算HashCode
HashSet:实现了Set接口、存储的是对象、调用add方法添加对象、HashSet调用成员对象来计算HashCode、因为hashCode可能相同,所以会在调用equals方法比较。
Hashtable:
1、线程安全的
2、不允许键值为null ---->抛出NUllPotnterException
3、默认初始化大小是11,如果指定就会是你指定的值。
面试题:
ConcurrentHashMap和Hashtable的区别?
1、底层数据结构:
ConcurrentHashMap:分段式数组+链表
Hashtable:数组+链表
2、两个都是线程安全、但是实现方式不同
ConcurrentHashMap:实现分段管理,对每个HashEntry进行加锁管理,这样就不会存在锁竞争、提高并发访问率
Hashtable:一把锁管所有。
LinkedHashMap:
底层:数组+链表/红黑树(加了一个双向链表)、保持键值对的插入顺序、同时通过对链表的相应操作实现了对访问顺序相关逻辑(就是在链表基础上加了双向链表可以看出顺序)、线程不安全。