记一次HashMap面试

记一次HashMap面试

从网上已经身边同事朋友的面试状况来看,面试HashMap几乎是必问的,网上也不少相似的文章,可是真面起来,发现仍是有不少点能够深抠的。本篇就结合一次面试经历说一下以前没有注意的点吧。java

HashMap的底层结构

这个相信不用我多说,你们都知道HashMap的底层是Node数组结构Node<K,V>[] table面试

扩容也不用我多说了,在size达到阈值(默认0.75的负载因子*容量)时触发扩容。数组

数组的capacity大小是2的x幂也无需多言,但这里多问一句为何是2的x幂而不是其余数呢?咱们知道,当一个key被放进到数组时须要明确本身被放在哪一个位置。最简单的固然就是对key进行hash以后h%n肯定。而若是数组的长度n是2的x幂,h%n这个操做与h&(n-1)是等价的,会更快。同时在扩容时,每一个key须要从新肯定本身在数组中的index,这时若是数组每一个位置的元素都变了一次,显然开销会比较大。可是若是n是2的x幂,那么在扩容变成2n后须要从新确认index时,对某个table[index]这个元素的新位置只有两种可能:1. 在原地不动(若是h&n的高位为0),2. index+nh&n的高位为1)。这样每一个元素移动的几率只有50%,显然会节约不少拷贝操做。框架

HashMap中链表转红黑树

这个也是高频问点,你们也基本都清楚,JDK1.8以后,若是某位置的链表长度大于某个阈值以后,就会转为红黑树,防止链表深度过大,从而查询时复杂度达到o(n)最坏状况。可是细问起来,若是没有认真看过putVal方法中每一行代码,真的有的地方可能会忽略。好比:ide

  1. 链表长度达到多少以后开始转链表?你可能脱口而出8。但真的超过这个阈值8以后就会转树吗?咱们跟进代码后会发现:还有另外一个条件,即数组的长度若是小于MIN_TREEIFY_CAPACITY默认64这个值,会触发一次扩容而并不会执行转树操做,因此链表的长度是能够超过8的。
final void treeifyBin(Node<K,V>[] tab, int hash) {
        int n, index; Node<K,V> e;
        if (tab == null || (n = tab.length) < MIN_TREEIFY_CAPACITY)
            resize();
        else if ((e = tab[index = (n - 1) & hash]) != null) {
            TreeNode<K,V> hd = null, tl = null;
            do {
                TreeNode<K,V> p = replacementTreeNode(e, null);
                if (tl == null)
                    hd = p;
                else {
                    p.prev = tl;
                    tl.next = p;
                }
                tl = p;
            } while ((e = e.next) != null);
            if ((tab[index] = hd) != null)
                hd.treeify(tab);
        }
    }
  1. 在转成红黑树时,每一个key应该放在左子树仍是右子树?这个由什么肯定?由于HashMapkey并不要求是Comparable,而TreeMap很显然key是要知足Comparable的,那么此时新来一个TreeNode,左右肯定以什么为依据呢?
    面试时在次数被面试官坑了一把,其实咱们仔细想一想,咱们并不须要严格的肯定某个TreeNode应该挂在它父节点的左边仍是右边,挂在哪边均可以啊,只要我插入时按某个标准,查找时也按一样的标准,二者保持一致就能够了,对吧?跟到源代码,对于没有实现Comparablekey,比较一下hashCode就能够了。源码中的比较一句就是两个keyhashCode,使用的是System.identityHashCode(object)这个native方法。
static int tieBreakOrder(Object a, Object b) {
            int d;
            if (a == null || b == null ||
                (d = a.getClass().getName().
                 compareTo(b.getClass().getName())) == 0)
                d = (System.identityHashCode(a) <= System.identityHashCode(b) ?
                     -1 : 1);
            return d;
        }

后记

还有你们都耳熟能详的东西我就不赘述了,面后也思考了一下,基础仍是很重要,仍是有不少指的深刻思考的地方,必定要打牢基础,可能准备了不少框架原理实践什么的,若是基础的没答好,这些应用层的东西准备的再好,可能也没机会跟面试官聊了,固然在面试中如何去引导面试官这一点也很重要,俗话说的好,把对方拉倒跟我一个低智商区,而后用我丰富的经验战胜他,这一点很重要,之后要多注意。code

相关文章
相关标签/搜索