经验整理-1-HashMap-关键原理总结

HashMap的底层数据结构?

数组+链表+红黑树,默认容量=16(无参构造为0,但put首次会给16),负载因子=0.75,默认容量阀值=容量*负载因子=12,链表长度阀值(引入红黑树)=8----(7是比较值,6的话就会去掉红黑树)

HashMap的存取原理?(冲突有两种,一直是本身key已存在)

1)存,
容量为0时,调用resize()初始化默认容量=16
拿key值对数组长度hash取hashcode,来决定存储的数组索引位置,无冲突直接入数组。若有冲突,先判断Key本身是否重复了,如果重复了,覆盖旧的。如果不是这种冲突,则再判断,当前尾入口是红黑树的话,直接插入;如果不是这种冲突,再判断,是否要引入红黑树(链表长度阀值>8,引入红黑树,8时不加不减),不引入就插入链表。最后,,需要考虑下是否扩容(如果超过负载因子*容量的值,扩容向左位运算1位,重新hash所有值)

巧记:容量16,取hashcode,无冲突直接入数组;有冲突,Key重复就覆盖,其他入链表或红黑树。是否扩容

2)取
首先根据key的Hash值进行数组方面的寻找,数组没找到直接返回null,若找到这个数组之后,判断key是不是唯一(有无链表红黑树),如果key唯一(链表长度0),则直接返回,如果不唯一(链表长度>0),则遍历链表比较每个key,如果还没找到且存在红黑树,再直接调用getTreeNode(),使用获取对应key的data
巧记:先找到这个数组索引,若key不唯一,使用equals进行Hash值遍历判断

Java7和Java8的区别?

JDK 1.8 的优化目的主要是:减少 Hash冲突 & 提高哈希表的存、取效率:

1、java8之后链表有红黑树(log(n)效率快,原n)
2、表插法遇到多线程扩容时可能产生---环形链死循环
-----------多线程高并发同时扩容,前一个改了next的指向,影响后一个扩容的使用,造成环形链死循环。

为啥会线程不安全?

到put/get方法都没有加同步锁,多线程情况最容易出现的就是:无法保证上一秒put的值,下一秒get的时候还是原值,所以线程安全还是无法保证。

有什么线程安全的类代替么?

一般都会使用HashTable或者ConcurrentHashMap

有什么线程安全的类代替么?

一般都会使用HashTable或者ConcurrentHashMap
HashTable我看过他的源码,很简单粗暴,直接在方法上锁sychronized,锁的有点过分了;
ConcurrentHashMap我看过他的源码,销威好点,直接在方法里面的代码块上锁sychronized;

默认初始化大小是多少?为啥是这么多,都是2的幂?

答一:默认给16..
答一:因为官方要求是2的次方,方便对key进hash运算取hashCode值时,做位运算,比普通运算快很多。要求是2的次方,16只是作者觉得合适。
总结:  1 减少hash碰撞
             2 提高map查询效率
            3 分配过小防止频繁扩容
            4 分配过大浪费资源

HashMap的扩容方式?负载因子是多少?为什么是这么多?

扩容是对数组长度扩容,和链表没关系,只是链表上的数据要重新hash,可能不是一个链表上了(2个key也可能产生链表)

1、向左位运算一位(*2)。初始若用无参构造函数会默认给16.因为官方要求是2的次方,方便对key进hash运算取hashCode值时,做位运算,比普通运算快很多。要求是2的次方,16只是作者觉得合适。
这个1.7是直接*2,但1.8是当前容量12+16*n.
2、另外,这个扩容实际上,是要做数据Hash值扩容重排的:

 jdk1.7扩容是重新计算hash;jdk1.8是要看看原来的hash值新增的那个bit是1还是0好了,如果是0则索引没变,如果是1则索引变成"原索引+oldCap".这是jdk1.8的亮点,设计的确实非常的巧妙,即省去了重新计算hash值得时间,又均匀的把之前的冲突的节点分散到新的数组bucket上

   jdk1.7在rehash的时候,旧链表迁移到新链表的时候,如果在新表的数组索引位置相同,则链表元素会倒置,但是jdk1.8不会倒置

为什么链表的长度为8是变成红黑树?为什么为6时又变成链表?

HashMap中初始化大小为什么是16? 为什么链表的长度为8是变成红黑树?为什么为6时又变成链表?_坑里水库的博客-CSDN博客

解决树高度问题,提升查询是效率

HashMap的主要参数都有哪些?

容量、负载因子,table就是node类型的数组,里面放的数组元素可理解为链表形。

HashMap是怎么处理hash碰撞的?

一般引入链表来解决。不同的值hashcode相同时,会放入链表后面,1.8用尾插法,如果链表长度超过8还会放入红黑树(log(n)效率快)

hash的计算规则?

对数组长度进行hashhash的为什么要重写hashcode?

Object类equals默认比较两个对象的内存地址,我们想把它重写成对象值的比较(因为要比较hashcode值是否冲突)。
而hashcode是本地方法,hashcode是根据对象的内存地址经哈希算法得来的,不同的对象的内存地址和原来Object类equals是一样道理,比较地址是不相同的,.hashcode就不同,我们要改写hashcode方法,也比较其对象值
比如,Student类的重写后的equals方法和hashcode方法,现在有两个Student对象:
    Student s1=new Student("小明",18);    Student s2=new Student("小明",18);此时s1.equals(s2),重写后一定返回true,不重写hashcode就会不一样。
不满足hashcode规定的规则:两个对象相等其哈希值一定相等

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

java_爱吃肉

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值