首页 课程 师资 教程 报名

92%的同学都在搜索的hashmap面试题

  • 2023-02-03 14:12:13
  • 837次 动力节点

现在网上有关hashmap面试题的资料可以说是五花八门的,有的只有问题没有回答,有的有回答没有解答思路,这就让我们很难参考了。在我们的面试中除了要征服面试官,让面试官看到我们的技术功底,也是面试者之间的pk,面试的人再多,企业也只招收那么几名,所以,我们要展现出最好的优势。从面试题下手,可以很大程度上增加我们的就业机会。

hashmap面试题

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

加载因子设置为0.75而不是1,是因为设置过大,桶中键值对碰撞的几率就会越大,同一个桶位置可能会存放好几个value值,这样就会增加搜索的时间,性能下降,设置过小也不合适,如果是0.1,那么10个桶,threshold为1,你放两个键值对就要扩容,太浪费空间了。

2.HashMap的主要参数都有哪些?

    //默认的map大小,为2的n次幂
    static final int DEFAULT_INITIAL_CAPACITY(默认初始容量) = 1 << 4; // aka 16

   // 最大容量,指定的值超过 2的30次幂,默认使用这个值
    static final int MAXIMUM_CAPACITY (最大容量)= 1 << 30;

   //在构造函数中没有指定时使用的负载因子
    static final float DEFAULT_LOAD_FACTOR = 0.75f;

   //当链表长度为8时,使用以红黑树代替链表,红黑树的结点是链表长度的两倍,当比较短的时候,使用红黑树的效率其实并不高,根据泊松分布公式的统计结果,在结点数达到8时,适合使用红黑树
    static final int TREEIFY_THRESHOLD(恐吓的阈值) = 8;
  
// 红黑树转为链表的阈值
    static final int UNTREEIFY_THRESHOLD (非恐吓的阈值)= 6;

//链表转红黑树时数组的大小的阈值,即数组大小大于这个数字时且链表长度大于8才会转为红黑树,
//在数组长度小于64,不会转,而是进行扩容
    static final int MIN_TREEIFY_CAPACITY = 64(小的恐吓容量);

3.HashMap是怎么处理hash碰撞的?

如果key相同,则会替换key对应的内容最最小值,key不相同,则接到后面的链表,如果链表长度到达8且数组的长度大于64时,则将链表转为红黑树,如果数组长度小于64,则是进行扩容

4.hash的计算规则?

将对象的hashcode()方法返回的hash值,进行无符号的右移16位,并与原来的hash值进行按位异或操作,目的是将hash的低16bit和高16bit做了一个异或,使返回的值足够散列

在get和put的过程中,计算下标时,先对hashCode进行hash操作,然后再通过hash值进一步计算下标。

5.如何解决初始化,输入的值不是2的n次幂

    /**
     * Returns a power of two size for the given target capacity.
     */
    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;
    }

6.HashMap的数据插入原理是怎样的

面试者:如果你能按以下思路回答,堪称完美!

先判断数组是否为空,为空进行初始化;

不为空,计算 k 的 hash 值,通过(n - 1) & hash计算应当存放在数组中的下标 index;

查看 table[index] 是否存在数据,没有数据就构造一个Node节点存放在 table[index] 中;

存在数据,说明发生了hash冲突(存在二个节点key的hash值一样), 继续判断key是否相等,相等,用新的value替换原数据(onlyIfAbsent为false);

如果不相等,判断当前节点类型是不是树型节点,如果是树型节点,创建树型节点插入红黑树中;(如果当前节点是树型节点证明当前已经是红黑树了);

如果不是树型节点,创建普通Node加入链表中;判断链表长度是否大于 8并且数组长度是不是大于64,大于的话链表转换为红黑树;

插入完成之后判断当前节点数是否大于阈值,如果大于开始扩容为原数组的二倍。

以上7个步骤,不一定完全死记硬背,咱也背不下来,因此威哥的逻辑还是基于理解本质。

7.多线程情况下,调整 HashMap 的大小会有什么问题?

由于线程不安全的原因,在多线程条件下调整 HashMap 的大小时会存在多个 HashMap 对象的竞争关系,不知道要给哪一个调整大小。如此一来,多线程情况调整 HashMap 的大小就会陷入死循环的情况,在 Java1.5 以后就增加了 ConcurrentHashMap 的对象解决多线程等问题。

8.HashMap扩容机制是怎么样的,JDK7 与JDK8有什么不同吗?

首先,我们需要知道HashMap为什么需要扩容,道理很简单,HashMap底层是用数组+链表实现的,而数组是预先就已经分配好内存的,如果需要对数组进行扩容,需要重新开辟一个新的数组再将旧数组上的元素进行转移,如果不进行扩容,那么会导致HashMap的链表过长,查询效率降低,所以需要对数组进行扩容。

在JDK7中,HashMap扩容的条件是 (size >= threshold) && (null !=table[bucketIndex]) , size 为HashMap当前的容量, threshold 初始化值为12, table[bucketIndex] 代表所put进来的key所对应的数组上的元素,所以在JDK7中扩容条件是当当Put操操作传入的 作传入的Key值所对应的数组位置上不为空时并且当前容量大于等于了扩容的阈值时才进行扩容 值所对应的数组位置上不为空时并且当前容量大于等于了扩容的阈值时才进行扩容,JDK7中的扩容思路是:开辟一个新的数组,数组大小为原数组的两倍,然后再将数组上的链表与元素转移到新数组上,此过程可能会出现死锁。

JDK8中的扩容条件比JDK7中要少,只有当前容量大于等于了扩容的阈值时才进行扩容 当前容量大于等于了扩容的阈值时才进行扩容,并且扩容的思路也发生了变化,思路比较复杂。

以上就是“92%的同学都在搜索的hashmap面试题”,你能回答上来吗?如果想要了解更多的Java面试题相关内容,可以关注动力节点Java官网。

选你想看

你适合学Java吗?4大专业测评方法

代码逻辑 吸收能力 技术学习能力 综合素质

先测评确定适合在学习

在线申请免费测试名额
价值1998元实验班免费学
姓名
手机
提交