HashMap 和 HashTable 源码学习和面试总结
HashMap
基于散列表(数组)+链表实现的,时间复杂度平均能达到O(1)。无序的。适用于在Map中插入、删除和定位元素。
实现了Serializable 和 Cloneable接口
1.扩容
哈希表中的条目数超出了加载因子与当前容量的乘积时,则要对该哈希表提前进行resize 操作(即扩容),每次扩容为之前大小的2倍。
加载因子越大,对空间的利用更充分,冲突增加,查找效率会降低(链表长度会越来越长);
加载因子太小,那么表中的数据将过于稀疏(很多空间还没用,就开始扩容了),严重浪费。
每次扩容要复制所有链表,重新计算哈希表位置,消耗资源较大。
2.Key NULL
key为null,则将其添加到table[0]对应的链表中
key不为null,则同样先求出key的hash值,根据hash值得出在table中的索引,而后遍历对应的单链表,如果单链表中存在与目标key相等的键值对,则将新的value覆盖旧的value,且将旧的value返回,如果找不到与目标key相等的键值对,或者该单链表为空,则将该键值对插入到单链表的头结点位置
3.初始大小、加载因子
初始大小默认为16,应设置2的幂次的大小
因为在计算散列位置时 hashmap中 用 h&(length-1) 替代取模 散列均匀 效率高
按位与 时 length-1 始终为奇数 保证了 散列的均匀 ,length-1 若为偶数则最后一位为0 ,则仅能检出偶数散列值,导致散列不均匀。
4.同步错误
HashMap是线程不安全的
1.两个put的key发生了碰撞(hash值一样),那么根据HashMap的实现,这两个key会添加到数组的同一个位置,这样最终就会发生其中一个线程的put的数据被覆盖
2.多个线程同时检测到元素个数超过数组大小*loadFactor
多个线程同时对hash数组进行扩容,都在重新计算元素位置以及复制数据,但是最终只有一个线程扩容后的数组会赋给table,也就是说其他线程的都会丢失,并且各自线程put的数据也丢失。且会引起死循环的错误。
5.同步
HashMap也可以同步 Map m = Collections.synchronizeMap(hashMap);
SynchronizedMap类中使用了synchronized来保证对Map的操作是线程安全的
6.Java 8 对 HashMap 的改进
hash表中每个桶附带的链表长度默认超过8时,链表就转换为红黑树结构,提高HashMap的性能
红黑树的增删改是O(logn),而不是O(n)。
优化扩容算法不再重新计算hash值
Hashtable
实现了Serializable 和 Cloneable接口
加了synchronized Hashtable是线程安全的,单线程环境下它比HashMap要慢。
默认大小为11 加载因子为0.75
直接使用除留余数法 计算散列值
key和value都不允许为null
扩容时,将容量变为原来的2倍加1
TreeMap
基于红黑树(一种自平衡二叉查找树)实现的,时间复杂度平均能达到O(log n)。有序的。适用于按自然顺序或自定义顺序遍历键(key)。
多使用HashMap,在需要排序的Map时候才用TreeMap。
ConcurrentMap
不可以有null键,线程安全,原子操作
一个ConcurrentHashMap 由多个segment 组成,每个segment 包含一个Entity 的数组。这里比HashMap 多了一个segment 类。该类继承了ReentrantLock 类,所以本身是一个锁。当多线程对ConcurrentHashMap 操作时,不是完全锁住map, 而是锁住相应的segment 。这样提高了并发效率。缺点:当遍历ConcurrentMap中的元素时,需要获取所有的segment 的锁,使用遍历时慢。锁的增多,占用了系统的资源。
LinkedHashMap
是HashMap的一个子类
LinkedHashMap保存了记录的插入顺序,在用Iterator遍历LinkedHashMap时,先得到的记录肯定是先插入的.也可以在构造时用带参数,按照应用次数排序。
ArrayList
实现了基于动态数组的数据结构
适合随机访问
二分查找使用的随机访问策略,适用ArrayList
在列表前部或中间插入 消耗较大
LinkedList
基于链表的数据结构
适合在表的前部和中部 插入删除
ArrayList占的空间在于本身和多余的扩充那部分
LinkedList占的空间在于每一个元素都需要消耗相当的空间 ,每个Entry对象 存储了上一个元素和下一个元素
Vector
Vector的方法都是同步的(Synchronized),是线程安全的(thread-safe)
扩容Vector 翻倍