HashMap几个很重要的问题

简介: 《基础》系列

HashMap数组的长度为什么是 2 的幂次方?

2 的 N 次幂有助于减少碰撞的几率。如果 length 为2的幂次方,则 length-1 转化为二进制必定是11111……的形式,在与h的二进制与操作效率会非常的快,而且空间不浪费。我们来举个例子,看下图

image.png

当 length =15时,6 和 7 的结果一样,这样表示他们在 table 存储的位置是相同的,也就是产生了碰撞,6、7就会在一个位置形成链表,4和5的结果也是一样,这样就会导致查询速度降低。

如果我们进一步分析,还会发现空间浪费非常大,以 length=15 为例,在 1、3、5、7、9、11、13、15 这八处没有存放数据。因为hash值在与14(即 1110)进行&运算时,得到的结果最后一位永远都是0,即 0001、0011、0101、0111、1001、1011、1101、1111位置处是不可能存储数据的。

再补充数组容量计算的小奥秘。

HashMap 构造函数允许用户传入的容量不是 2 的 n 次方,因为它可以自动地将传入的容量转换为 2 的 n 次方。会取大于或等于这个数的 且最近的2次幂作为 table 数组的初始容量,使用tableSizeFor(int)方法,如 tableSizeFor(10) = 16(2 的 4 次幂),tableSizeFor(20) = 32(2 的 5 次幂),也就是说 table 数组的长度总是 2 的次幂。JDK 8 源码如下:

static final int tableSizeFor(int cap) {
        int n = cap - 1;
        n |= n >>> 1;
        n |= n >>> 2;
        n |= n >>> 4;
        n |= n >>> 8;
        n |= n >>> 16;
        return (n < 0) ? 1 : (n >= MAXIMUM_CAPACITY) ? MAXIMUM_CAPACITY : n + 1;
    }

让cap-1再赋值给n的目的是另找到的目标值大于或等于原值。例如二进制1000,十进制数值为8。如果不对它减1而直接操作,将得到答案10000,即16。显然不是结果。减1后二进制为111,再进行操作则会得到原来的数值1000,即8。

10、HashMap 的put方法流程?

以JDK 8为例,简要流程如下:

1、首先根据 key 的值计算 hash 值,找到该元素在数组中存储的下标;

2、如果数组是空的,则调用 resize 进行初始化;

3、如果没有哈希冲突直接放在对应的数组下标里;

4、如果冲突了,且 key 已经存在,就覆盖掉 value;

5、如果冲突后,发现该节点是红黑树,就将这个节点挂在树上;

6、如果冲突后是链表,判断该链表是否大于 8 ,如果大于 8 并且数组容量小于 64,就进行扩容;如果链表节点大于 8 并且数组的容量大于 64,则将这个结构转换为红黑树;否则,链表插入键值对,若 key 存在,就覆盖掉 value。


11、HashMap 的扩容方式?

image.png

HashMap 在容量超过负载因子所定义的容量之后,就会扩容。

详情参照这篇

12、一般用什么作为HashMap的key?

一般用Integer、String 这种不可变类当作 HashMap 的 key,String 最为常见。

  • 因为字符串是不可变的,所以在它创建的时候 hashcode 就被缓存了,不需要重新计算。
  • 因为获取对象的时候要用到 equals() 和 hashCode() 方法,那么键对象正确的重写这两个方法是非常重要的。Integer、String 这些类已经很规范的重写了 hashCode() 以及 equals() 方法。

#13、HashMap为什么线程不安全?

  • JDK 7 时多线程下扩容会造成死循环。
  • 多线程的put可能导致元素的丢失。
  • put和get并发时,可能导致get为null。
相关文章
|
6月前
|
存储 安全 Java
HashMap的详细解读
HashMap的详细解读
58 0
|
6月前
|
存储 算法 索引
|
6月前
|
Dart 算法 Java
HashMap的0.75可能只是一个经验值
HashMap的0.75可能只是一个经验值
|
存储 算法
详解HashMap
1.hash code hash code是使用hash函数运算得到的一个值,是对象的身份证号码,用于对象的辨重。在同一运行周期,对同一个对象多次调用hashcode(),只要是用于equals()的内容未变,那么每次得到的hash码也应该不变。,但不同运行周期间hash码可能会不同。
109 0
|
存储 算法 安全
【HashMap】
【HashMap】
127 0
|
存储 安全 Oracle
HashMap你真的了解吗?
HashMap你真的了解吗?
120 0
HashMap你真的了解吗?
|
存储 安全 算法
再聊 HashMap
HashMap特点: KV 结构,K、V 都允许 null 值; 线程不安全,运行速度快,存取速度快; 非线程安全的
再聊 HashMap
|
安全 算法 数据挖掘
厉害了!把 HashMap 剖析的只剩渣了!
很高兴遇见你~ HashMap是一个非常重要的集合,日常使用也非常的频繁,同时也是面试重点。本文并不打算讲解基础的使用api,而是深入HashM
厉害了!把 HashMap 剖析的只剩渣了!
HashMap 中的一个“坑”!(1)
HashMap 中的一个“坑”!(1)
174 0
HashMap 中的一个“坑”!(1)
HashMap 中的一个“坑”!(3)
HashMap 中的一个“坑”!(3)
215 0
HashMap 中的一个“坑”!(3)