Map
map是一种key,value结构,key是键,value是值,也就是键值对结构.
这是Map的继承体系
HashMap(数组+链表+红黑树)
特点:
1.键值对,<key,value>结构
2.key值是根据键的hash值计算的,并且键是唯一的.
3.value是任意类型的.
4.底层是数组加链表的形式.当key’的hash值相同时,发生hash碰撞,再用equals()方法判断是否相同,如果相同则覆盖,如果不同则生成链表.当链表长度大于8时,链表变成红黑树.
5.hashMap为线程不安全的数据结构.如果多线程可能造成hash碰撞时链表中的两个节点互相指定.形成循环链.
jdk1.7时hashMap的实现
大方向上,HashMap 里面是一个数组,然后数组中每个元素是一个单向链表。上图中,每个绿色的实体是嵌套类 Entry 的实例,Entry 包含四个属性:key, value, hash 值和用于单向链表的 next。
- capacity:当前数组容量,始终保持 2^n,可以扩容,扩容后数组大小为当前的 2 倍。
- loadFactor:负载因子,默认为 0.75。
- threshold:扩容的阈值,等于 capacity * loadFactor
jdk1.8时hashMap的实现
最大的不同就是利用了红黑树,所以其由 数组+链表+红黑
树 组成。
根据 Java7 HashMap 的介绍,我们知道,查找的时候,根据 hash 值我们能够快速定位到数组的具体下标,但是之后的话,需要顺着链表一个个比较下去才能找到我们需要的,时间复杂度取决于链表的长度,为 O(n)。为了降低这部分的开销,在 Java8 中,当链表中的元素超过了 8 个以后,
会将链表转换为红黑树,在这些位置进行查找的时候可以降低时间复杂度为 O(logN)。
hashMap的参数:
节点Node类,定义在hashMap的内部类,这是一个单向链表
节点数组,node<K,V>[]
常用方法
添加
put(K,V) 添加
putAll(collection c)添加集合
删除
remove(K)
clear()清空
获取
get(K) 获取value
keySet() 获取key的集合
values() 获取value值得集合
entrySet()获取节点的集合
查询
containsKey(K) 查询是否存在key
containsValue(V) 查询是否存在value值
isEmpty() 查询是否为空 替换 replace(K,V) 替换
hashMap的遍历方式:
//第一种遍历,通过key的集合
for(Object i : map.keySet())
{
System.out.println(map.get(i));
}
//第二种遍历,通过节点entry的集合
for(Map.Entry<Integer, String> entry: map.entrySet()) {
System.out.println(entry.getKey());
System.out.println(entry.getValue());
}
//第三种遍历,通过遍历器
Iterator<Map.Entry<Integer, String>> it = map.entrySet().iterator();
while(it.hasNext()) {
Map.Entry<Integer, String> en = it.next();
System.out.println(en.getKey());
System.out.println(en.getValue());
}
//第四种遍历,通过value的集合
for(Object o : map.values()) {
System.out.println(o);
}
HashTable(线程安全)
特点:
1.大部分方法和hashMap相似
2.线程安全的
3.性能低的,我们如果想保证线程安全,一般使用ConcurrentHashMap对象
put方法加锁
get方法也加锁
TreeMap(可排序)
特点:
1.key 和value结构
2.数据按照key值排序.所以key值必须实现comparable接口,重写compareTo方法.
3.treeSet是在treeMap的基础之上实现的.
常用方法:略
LinkHashMap(记录插入顺序)
特点:
1.在hashMap的基础之上,他保证了插入的hash表的有序行.
实现方式,可以在put方法里,现将key值放入一个linkedList集合中去,遍历的时候先从LinkedList集合中取key值,再拿取到的key值去map中取value值.
ConcurrentHashMap(线程并发安全的map集合)
Segment 段
ConcurrentHashMap 和 HashMap 思路是差不多的,但是因为它支持并发操作,所以要复杂一些。整个ConcurrentHashMap 由一个个 Segment 组成,Segment 代表”部分“或”一段“的意思,所以很多地方都会将其描述为分段锁。注意,行文中,我很多地方用了“槽”来代表一个segment
线程安全(Segment 继承 ReentrantLock 加锁)
简单理解就是,ConcurrentHashMap 是一个 Segment 数组,Segment 通过继承 ReentrantLock来进行加锁,所以每次需要加锁的操作锁住的是一个 segment,这样只要保证每 个 Segment 是线程安全的,也就实现了全局的线程安全。
并行度(默认 16)
concurrencyLevel:并行级别、并发数、Segment 数,怎么翻译不重要,理解它。默认是 16, 也就是说ConcurrentHashMap 有 16 个 Segments,所以理论上,这个时候,最多可以同时支 持 16个线程并发写,只要它们的操作分别分布在不同的 Segment 上。这个值可以在初始化的时候设置为其他值,但是一旦初始化以后,它是不可以扩容的。再具体到每个 Segment 内部,其实 每个 Segment 很像之前介绍的HashMap,不过它要保证线程安全,所以处理起来要麻烦些。
Java8 实现 (引入了红黑树)
Java8 对 ConcurrentHashMap 进行了比较大的改动,Java8 也引入了红黑树。
来源:CSDN
作者:古龙(leo)
链接:https://blog.csdn.net/weixin_45449911/article/details/104497317