1.两个工具的Hashcode值相等,但是两个工具的内容值不一定相等;---Hash冲突的问题
2.两个工具的值Equals比较相等的情形下,则两个工具的Hashcode值一定相等;
3.重写Equals不重写HashCode随意马虎导致内存泄露

数组+链表
4.HashMapKey为null存放在什么位置数组为0的位置
5.HashMap如何办理Hash冲突问题HashMap底层是通过链表来办理hash冲突的
static final int hash(Object key) {int h;return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);}((p = tab[i = (n - 1) & hash])
1、担保不会发生数组越界首先我们要知道的是,在HashMap,数组的长度按规定一定是2的幂。因此,数组的长度的二进制形式是:10000…000, 1后面有偶数个0。 那么,length - 1 的二进制形式便是01111.111, 0后面有偶数个1。最高位是0, 和hash值相“与”,结果值一定不会比数组的长度值大,因此也就不会发生数组越界。一个哈希值是8,二进制是1000,一个哈希值是9,二进制是1001。和1111“与”运算后,结果分别是1000和1001,它们被分配在了数组的不同位置,这样,哈希的分布非常均匀。
6.HashMap底层采取单链表还是双链表单向链表
7.韶光繁芜度O(1)、O(N)、O(Logn)差异韶光繁芜度为O(n) 从头查询到尾部,查询多次韶光繁芜度为O(1) 查询一次 比如根据数组下标查询韶光繁芜度为O(logn) 平方查询 比如红黑树
8.HashMap根据key查询的韶光繁芜度韶光繁芜度 o(n) 从头遍历到尾部;韶光繁芜度o(1) 直接查询一次;
9.HashMap8扩容底层事理将原来的链表拆分两个链表存放; 低位还是存放原来index位置 高位存放index=j+原来长度我们在扩充HashMap的时候,只须要看看原来的hash值新增的那个bit是1还是0就好了,是0的话索引没变,是1的话索引变成“原索引+oldCap”
10.HashMap底层是有序存放的吗无序
11.LinkedHashMap 和 TreeMap底层如何实现有序LinkedHashMap基于双向链表实现HashMap基本单向链表实现TreeMap基于红黑树底层实现
12.HashMap底层如何降落Hash冲突概率static final int hash(Object key) {int h;return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);}((p = tab[i = (n - 1) & hash])
13.谈一下HashMap中hash函数是怎么实现的?还有哪些hash函数的实现办法?(1)hash函数的实现:对key的hashCode做hash操作,与高16位做异或运算。(2)其他hash函数实现办法:还有平方取中法,除留余数法,伪随机数法。
14.为什么不直接将key作为哈希值而是与高16位做异或运算?由于如果直策应用key作为哈希值的话,当产生key的哈希值高位变革大低位变革小的情形时,会发生严重的哈希冲突,可能须要扩容或转化为红黑树构造,影响HashMap的性能。而如果和高16位做异或运算,就能同时用上高十六位和第十六位,增加了随机性,减少哈希冲突的次数。
15.HashMap如何存放1万条key效率最高参考阿里巴巴官方手册:
(须要存储的元素个数 / 负载因子) + 110000/0.75+1=13334正常如果存放1万个key的情形下 大概扩容10次=16384
16.modCount的浸染我们知道 java.util.HashMap 不是线程安全的,因此如果在利用迭代器的过程中有其他线程修正了map,那么将抛出ConcurrentModificationException,这便是所谓fail-fast策略。这一策略在源码中的实现是通过 modCount 域,modCount 顾名思义便是修正次数,对HashMap 内容的修正都将增加这个值,那么在迭代器初始化过程中会将这个值赋给迭代器的 expectedModCount。在迭代过程中,判断 modCount 跟 expectedModCount 是否相等,如果不相等就表示已经有其他线程修正了 Map:
17.HashMap在这里插入代码片1.8如何避免多线程扩容去世循环问题/ Transfers all entries from current table to newTable./void transfer(Entry[] newTable, boolean rehash) {//新数组长度int newCapacity = newTable.length;//table为旧表,此处为遍历Hash表,落在桶上的所有节点!也便是链表头结点!for (Entry<K,V> e : table) {while(null != e) {Entry<K,V> next = e.next;//此处为多线程下,发生问题的点!非常主要,牢记!if (rehash) {//重新进行Hash打算,这个if方法不用管!e.hash = null == e.key ? 0 : hash(e.key);}int i = indexFor(e.hash, newCapacity);//重新打算这个节点放在新newTable表的位置!//这3段代码, 通过下面的图来阐明!e.next = newTable[i];newTable[i] = e;e = next;}}}
扩容形成环形列表,get时导致去世循环。
18.什么情形下,须要从红黑树转换成链表存放?JDK1.8中,HashMap采取数组+链表+红黑树实现,当链表长度超过阈值(8)时,将链表转换为红黑树,这样大大减少了查找韶光。
当链表的长度>=8且数组长度>=64时,会把链表转化成红黑树。
当链表长度>=8,但数组长度<64时,会优前辈行扩容,而不是转化成红黑树。
当红黑树节点数<=6,自动转化成链表。
18.为什么加载因子是0.75而不是1产生背景:减少Hash冲突index的概率;查询效率与空间问题;
大略推断的情形下,提前做扩容:1.如果加载因子越大,空间利用率比较高,有可能冲突概率越大;2.如果加载因子越小,有可能冲突概率比较小,空间利用率不高;空间和韶光上平衡点:0.75统计学概率:泊疏松布是统计学和概率学常见的离散概率分布
19.ConcurrentHashMap底层实现的事理https://blog.csdn.net/u014401141/article/details/81258753
20.hashMap中put是如何实现的?分为三大步,一是打算出元素在数组中的存储索引位置,二是将数据保存到table数组中,三是修正某些成员变量的值并根据情形判断是否扩容。
①首先要根据键值key打算出哈希值,然后通过位运算实现哈希值的取模,以得到元素在数组中的索引位置。②如果是第一次插入数据(在jdk1.8之后),还要先通过resize()方法对数组进行初始化。①判断将要存储的数组位置是否已经存在元素,不存在则解释没有发生哈希碰撞,直接将元素添加到数组中。②存在则解释发生了哈希碰撞,须要依次进行以下判断:a.是否是相同的key值,是则覆盖掉旧值更换为新值;b.是否是红黑树构造,是则直接插入;c.以上判断均不符合,解释是链表构造,则遍历链表在尾部进行插入,在这个过程中如果检讨到相同key值元素则直接更换旧值,如果插入元素后链表长度大于阈值则考试测验转化为红黑树。代表元素个数的size加一,代表修正次数的modCount加一,size超过临界值则进行扩容。
关键词:打算索引位置,保存数据到数组(依次判断:数组索引位置有无元素;key值是否相同;节点类型),扩容。在这里插入图片描述(图来自https://www.cnblogs.com/LiaHon/p/11149644.html)
21.HashMap中什么时候须要进行扩容,扩容resize()又是如何实现的?(1)扩容机遇:
初始化数组(jdk1.8之后,默认在第一次插入数据的时候才进行数组初始化,初始化是通过调用扩容方法实现的);当元素个数超过临界值(临界值=装载因子数组容量);当链表长度超过默认阈值8,考试测验转化为红黑树,但创造数组长度不到64时。
(2)扩容机制:
如果数组未初始化过,会将数组的容量和装载因子都设置为默认值,并将数组创建出来。如果数组初始化过,扩容会分配一个新的数组,新的数组长度翻倍,然后遍历全体老构造将元素重新哈希映射到新的数组里。HashMap在进行扩容时,利用的重新哈希的办法非常奥妙,由于每次扩容都是翻倍,与原来打算的 (数组长度-1)&hash 的结果比较,只是多了一个bit位,以是结点要么就在原来的位置,要么就被分配到"原位置+旧容量"这个位置。