1.HashMap的结构和底层原理
HashMap是由数组和链表组合构成的数据结构,它的存储是key-value键值对的形式存储的。跟据key的Hash去计算index下标,也就是插入的位置。
2.为什么会出现链表?
数组的长度是有限的,哈希本身存在概率性,极端会出现俩个key会Hash到同一个值,就会出现链表。
3.在新的Entry节点是怎样插入链表中的?
Java8之前是采用头插,新来的值会代替原来的值,原来的值就会到链表当中。
Java8之后采用的是尾插(因为头插,多线程插入可能会出现循环链表,取值时出现——Infinite Loop)
4.HashMap的默认初始长度?
16 1<<4
5.HashMap是如何扩容的?
扩容:创建⼀个新的Entry空数组,⻓度是原数组的2倍。
ReHash:遍历原Entry数组,把所有的Entry重新Hash到新数组。
负载因子0.75f,假如长度为100,当插入76个数据的时候就要进行扩容了
随着数组的长度改变,hash规则也将改变,所以需要hash而不是复制
6.Java8之后是不就可以把HashMap用到多线程当中了?
虽然不会出现循环链表取不到值,但是在源码当中put/get没有加同步锁,意味着上一秒put的值下一秒get的还是原值,线程的安全无法保证。
7.为什么不直接写16长度,而是采用位运算符?
提高性能
实现hash的均匀分布
8.为啥我们重写equals⽅法的时候需要重写hashCode⽅法呢?
因为在java中,所有的对象都是继承于Object类。Ojbect类中有两个⽅法equals、hashCode,这两个⽅法都是⽤来⽐较两个对象是否相等的。在未重写equals⽅法我们是继承了object的equals⽅法,那⾥的 equals是⽐较两个对象的内存地址,显然我们new了2个对象内存地址肯定不⼀样。
对于值对象,==⽐较的是两个对象的值
对于引⽤对象,⽐较的是两个对象的地址
HashMap是通过key的hashCode去寻找index的,那index⼀样就形成链表了,我们去get的时候,他就是根据key去hash然后计算出index,找到了2,里面有不同的key,我们取哪个呢??所以如果我们对equals⽅法进⾏了重写,建议⼀定要对hashCode⽅法重写,以保证相同的对象返回相同的hash值,不同的对象返回不同的hash值。不然⼀个链表的对象,你哪⾥知道你要找的是哪个,到时候发现hashCode都⼀样,这不是完犊⼦嘛。