HashMap相关知识回顾

HashMap底层原理

  • jdk1.7的时候是数组+链表;jdk1.8的时候是数组+链表+红黑树
  • jdk1.7的时候是无冲突放进数组有冲突放进链表;jdk1.8的时候是无冲突放进数据,有冲突链表长度小于8放进链表,大于8放进红黑树。
  • jdk1.7是头插法;jdk1.8是尾插法。
  • 在jdk1.6、jdk1.7中,HashMap采用位桶+链表实现,即使用链表处理冲突。同一hash值得链表都存储在一个链表里,但当位于一个桶中的元素较多时,即hash值相同的元素较多时,通过key值依次查找的效率较低。而jdk1.8中,HashMap采用位桶+链表+红黑树实现,当链表长度超过阈值(8)时,且数组长度超过64,链表转换为红黑树,这样大大减少了查找时间。
  • (jdk1.8中链表长度超过8时为什么使用红黑树)在链表节点中数是8时的概率是千分之一,此时链表的性能已经非常的差了,所以转换为红黑树,来提高性能。

HashMap默认加载为什么选择0.75?

提高空间利用率和减少查询成本的这种,主要是泊松分布,0.75的话碰撞最小。

对比:

  • 加载因子过高。例如1,虽然减少了空间开销,提高了空间利用率,但同时增加了查询时间成本。
  • 加载因子过低。例如0.5,虽然可以减少查询时间成本,但是空间利用率很低,同时提高了rehash操作的次数。

ArrayList和LinkedList的区别

  • ArrayList是基于数组实现的;LinkedList是基于链表实现的。
  • ArrayList的查询效率比LinkedList高(因为数组是有序的,LinkedList是无序的,查询后者时需要移动指针)
  • LinkedList的插入删除效率比ArrayList要高(因为数组插入删除需要移动下标,对所有的数据下标进行影响,移动数据)

为什么HashMap是线程不安全的?

jdk1.7的时候在多线程的情况下容易出现死循环和丢失数据的情况,主要是因为HashMap冲突时使用的是头插法,也就是链表顺序会翻转,这是形成死循环的关键点。
jdk1.8的时候对HashMap进行了优化,但是HashMap在多线程的情况下任然是线程不安全的,容易出现数据覆盖的情况。比如说线程A和线程B同时进行put操作,线程A还没插入操作就进入挂起状态,这个时候线程B正常执行,获取线程A的CPU时间片,线程A继续进行插入操作,但是不用再进行hash判断,那么线程A就会把线程B的数据给覆盖掉。
解决方法:
Collections中有SynchronizedMap()和SynchronizedSet()方法。还可以使用CopyOnWriteArraySet<>()和ConcurrentHashMap<> ()方法。

HashMap和HashTable有什么区别?

  • HashMap是线程不安全的;HashTable是线程安全的。
  • 由于HashTable线程安全,所以在效率上,HashTable比不上HashMap。
  • HashMap最多只允许一条记录的键为null,允许多条记录的值为null;而HashTable不允许。
  • HashMap的初始化数组长度是16,扩容后,扩容两倍;HashTable的初始化数组长度是11,扩容后,扩容两倍+1.
  • HashMap需要重新计算hash值;HashTable直接使用对象的hashcode。

为什么HashTable是线程安全的?

HashTable的源码中,remove、get、put方法都加入了synchronized关键字,做成了同步方法,保证了线程安全。

为什么HashTable效率低?

因为HashTable的操作方法都做了同步控制,虽然保证了线程安全,但是带来的结果就是任何一个时刻只能有一个线程控制HashTable,所以HashTable效率比较低。

为什么synchronized可以保证线程安全(synchronized底层原理)?

synchronized代码中来讲就是说,线程1进入后,其他线程就不能进入也就是加锁,必须要等线程1出来后(释放锁),其他线程争抢到线程1的返回值才能进入,以此类推,所以可以保证线程是安全的。

HashMap和ConcurrentHashMap的区别

除了加锁,原理上两者之间无太大的区别。另外,HashMap的键值对允许有null,但是ConcurrentHashMap不允许。

ConcurrentHashMap底层原理(jdk1.7和jdk1.8的区别)

  • jdk1.7中ConcurrentHashMap是由Segment(可重入锁)数组结构和HashEntry(存储键值对数据)数组结构组成的。
  • jdk1.8中放弃了Segment,取而代之的是Node+CAS+Synchronized来保证并发安全。

HashMap和HashSet的区别

  • HashMap实现了Map接口;HashSet实现了Set接口。
  • HashMap存储键值对;HashSet仅仅存储对象。
  • HashMap使用put()方法将元素放入Map中;HashSet使用add()方法将元素放入Set中。
  • HashMap使用键对象来计算hashcode值;HashSet使用成员方法来计算hashcode值(对于两个对象来说,hashcode值可能相同,所以equals()方法用来判断对象的相等性,如果两个对象不同的话,返回false)。
  • HashMap比较快,因为是使用唯一的键来获取值;HashSet较HashMap来说比较慢。

List去重的五种方式

  1. 使用LinkedHashSet删除arraylist中的重复数据。
  2. 使用java8新特性stream进行list去重。
  3. 利用HashSet不能添加重复数据的特性,由于HashSet不能保证添加顺序,所以只能作为判断条件保证顺序。
  4. 利用List的contains方法循环遍历,重新排序,只添加一次数据避免重复。
  5. 双重for循环去重。

Hash解决冲突的方式

开放定址法:
当冲突发生时,使用某种探查(亦称探测)技术在散列表中形成一个探查(测)序列。沿此序列逐个单元地查找,直到找到给定的关键字,或者碰到一个开放的地址(即该地址单元为空)(若要插入,在探查到开放的地址,则可将待插入的新结点存人该地址单元)。查找时探查到开放的地址,则表明表中无待查的关键字,即查找失败。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值