面试题-Hashmap相关

一、实现原理

HashMap基于哈希表的Map接口实现,是以key-value存储形式存在,即主要用来存放键值对。HashMap的实现是不同步的,这意味着他不是线程安全的,它的key,value都可以为null

JDK1.8之前HashMap由数组+链表组成。数组是HshMap的主体,链表则是主要为了解决哈希冲突(两个对象调用的hashCode方法计算的哈希值一致导致计算的数组索引值相同(哈希寻址算法[hash&length-1]))而存在的(“拉链法”解决冲突)
JDK1.8以后在解决哈希冲突时有了较大的变化,当链表长度大于阈值(或者红黑树的边界值,默认为8,且数组中桶的数量大于64,此时此索引位置上的所有数据改为使用红黑树存储)
jdk 1.8之后 数组+链表+红黑树

(1)在 new HashMap 的时候,底层并没有创建数组

(2)在首次调用put()方法的时候,底层会创建一个长度为16的数组

(3)用数组容量乘以加载因子会得到一个阈值

加载因子 0.75

hash冲突一旦数组中存储的元素个数超过该阈值进行扩容,通过rehash()方法将原来的数组扩容为之前的两倍,在做扩容的时候会生成一个新的数组,原来所有的数据需要重新计算哈希值然后重新分配到新的数组,所以扩容的话会十分消耗性能。

哈希冲突,不同的对象算出来的下标相同就会产生哈希冲突。

存储的是entry对象

为什么加载因子设置为0.75,初始化临界值是12


默认的数组大小为16,加载因子为0.75

0.75是对空间和时间效率的一种平衡选择。

如果负载因子小一些比如是0.4,那么初始长度16*0.4=6,数组占满6个空间就进行扩容,很多空间可能元素很少甚至没有元素,会造成大量的空间被浪。

如果负载因子大一些比如是0.9,这样会导致扩容之前查找元素的效率非常低。

oadfactory设置为0.75是经过多重计算检验得到的可靠值,可以最大程度的减少rehash的次数,避免过多的性能消耗。


HashMap的判断机制


当链表长度超过8的时候,此时会继续判断数组的长度是否小于64。
如果数组长度小于64,会扩容,如果大于等于64,就会将链表转换为红黑树,提高查询的效率。
当红黑树节点小于等于6时又会退化为链表。

但是在hashMap进行扩容的时候会重新创建一个数组复制进去,所以扩容的效率非常低。

map.put实现原理


首先通过k的hashCode()方法得出哈希值,通过哈希算法转为数组下标。
/
如果数组下标位置没有元素,就直接添加元素。如果下标对应位置上有链表的话,就会拿k跟链表上所有的k进行equals比较,如果都返回false,就将新元素追加到链表的尾部。
/
如果其中有一个equals返回true,就会将这个节点的value覆盖
 

map.get实现原理


首先通过k的hashCode()方法得出哈希值,通过哈希算法转为数组下标。
/
如果数组下标位置没有元素,就直接返回null。如果下标位置上有链表的话,就会拿k跟链表上所有的k进行equals比较,如果都返回false,就直接返回null。
/
如果有一个返回true,就返回这个节点的value值。

链表使用头插法还是尾插法,为什么?

jdk1.8是尾插法 之前是头插法(例如jdk1.6)

尾插法就是将 node节点插入到之前数据的next

头插发就是将之前的node节点放在新的node节点的next上

线程安全的集合

弃用的vector

Java 中有 HashTable、Collections.synchronizedMap、以及 ConcurrentHashMap 可以实现线程安全的 Map。

HashTable 是直接在操作方法上加 synchronized 关键字,锁住整个数组,粒度比较大,Collections.synchronizedMap 是使用 Collections 集合工具的内部类,通过传入 Map 封装出一个 SynchronizedMap 对象,内部定义了一个对象锁,方法内通过对象锁实现;ConcurrentHashMap 使用分段锁,降低了锁粒度,让并发度大大提高。

为什么hashMap key值可以为Null

ConcurrentHashmap和Hashtable都是支持并发的,这样会有一个问题,当你通过get(k)获取对应的value时,如果获取到的是null时,你无法判断,它是put(k,v)的时候value为null,还是这个key从来没有做过映射。HashMap是非并发的,可以通过contains(key)来做这个判断。而支持并发的Map在调用m.contains(key)和m.get(key),m可能已经不同了。
 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值