記一次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

相關文章
相關標籤/搜索