JAVA常用map及区别
map是java中十分常用的一种结构,并且在面试时经常会问到,于是在此整理一些常用的map。
HashMap
HashMap几乎是最常用的map类,没有之一,进行键值对封装大部分使用的都是HashMap,其特点如下:
- 线程不安全;
- 数据无序;
- 允许key和value为null;
- 继承自AbstractMap类,实现了map接口
- 存储结构:数组+链表+红黑树(1.8以后,链表长度大于8转换为红黑树)。插入数据时,通过hashcode找到这个键值对所处的bucket,如果发生冲突,则通过linkedlist的方式存储mapEntry对象,mapEntry实际上是一个键值对,在查询时,相同hashcode的key就是通过mapEntry进行比较然后找到对应的value。在链表长度大于8以后转换为红黑树结构。
- 负载因子默认为0.75,当hashmap中的数据量达到总容量*负载因子时,hashmap会进行扩容。 负载因子为0.75是为了提高空间利用率和 减少查询成本的折中,主要是泊松分布,0.75的话碰撞最小。
- HashMap扩容一次容量会变为原来的二倍,其通过hash运算结果和长度二进制量进行与运算计算应该放在数组的哪个位置,如果容量为2的n次幂,可以降低冲突。
LinkedHashMap
- 线程不安全
- 数据保存了插入顺序
- 继承自HashMap,扩容机制一致
- 遍历时速度低于HashMap,但是在HashMap容量非常大但数据非常少时可能例外。LinkedHashMap的遍历速度只和实际数据有关,和容量无关,而HashMap的遍历速度和他的容量有关。
TreeMap
- 线程不安全
- 数据有序
- 不允许key为null,因为treemap有序,需要通过comparable和Comparator比较数据。
- 底层实现为红黑树,容量没有限制
HashTable
- 线程安全(因为其中方法都是synchronized修饰的)
- 数据有序
- 继承自Dictionary类,实现了map接口
- 不允许key为null,因为treemap有序,需要通过comparable和Comparator比较数据。
- 底层实现为红黑树,容量没有限制
ConcurrentHashMap
jdk1.5之后,java加入了concurrent包,其中就有一种常用的map结构concurrentHashMap,该类在hashmap的基础上,加上了线程安全的特性。
- 线程安全:其实现线程安全的方式与HashTable不同,该类在jdk1.7使用的是分段锁的概念,对每个分段实行同步机制,在两个线程读取不同的分段时可以异步操作。而在jdk1.8中进行了重构,舍弃了分段锁,采用无锁的算法进行同步。
- 实现了currentmap接口而不是map接口
- 不允许key或value为null
- 关于currenthashmap的源码解析,可以参照ConcurrentHashMap实现原理和JDK1.8 concurrentHashMap 同步机制难点解析进行学习