Java 集合

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 翻倍

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值