基于JDK1.7寫自己的HashMap--2020-11-21

一直對(duì)jdk的map內(nèi)部結(jié)構(gòu)很是困惑赡模,鼓起勇氣啃了源碼,自己寫了一個(gè)簡單版本map,希望對(duì)java小萌新有點(diǎn)幫助觅廓。

源碼

/**帶有自動(dòng)擴(kuò)容能力**/
public class myHashMapPlus<K, V> implements Map<K, V> {

    volatile int size = 0;
    private Entry<K, V>[] table;
    private static int DEFAULT_INITIAL_CAPACITY = 16;
    private int MAXIMUM_CAPACITY = Integer.MAX_VALUE;
    static final float DEFAULT_LOAD_FACTOR = 0.75f;
    private float loadFactor;
    /**size>ExpansiontThreshold擴(kuò)容【ExpansiontThreshold=capacity*2*DEFAULT_LOAD_FACTOR】**/
    private int expansiontThreshold;
    /**數(shù)組長度,size>ExpansiontThreshold擴(kuò)容[capacity=capacity*2]**/
    private int capacity;

    public myHashMapPlus() {
        this(DEFAULT_INITIAL_CAPACITY, DEFAULT_LOAD_FACTOR);
    }

    public myHashMapPlus(int initialCapacity) {
        this(initialCapacity, DEFAULT_LOAD_FACTOR);
    }

    public myHashMapPlus(int initialCapacity, float loadFactor) {
        if (initialCapacity < 0) {
            throw new IllegalArgumentException("Illegal initial capacity: " +
                    initialCapacity);
        }

        if (initialCapacity > MAXIMUM_CAPACITY) {
            initialCapacity = MAXIMUM_CAPACITY;
        }

        if(initialCapacity<DEFAULT_INITIAL_CAPACITY){
            initialCapacity=DEFAULT_INITIAL_CAPACITY;
        }

        if (loadFactor <= 0 || Float.isNaN(loadFactor)) {
            throw new IllegalArgumentException("Illegal load factor: " + loadFactor);
        }

        this.loadFactor = loadFactor;
        this.expansiontThreshold = (int) (initialCapacity * this.loadFactor);
        this.capacity = initialCapacity;
        this.table = new Entry[capacity];
    }

    /**
     * 通過key進(jìn)行hash
     * hash和數(shù)組長度得到index數(shù)組下標(biāo)
     * 判斷為空:直接存儲(chǔ)
     * 判讀不為空:沖突--用鏈表解決
     * 返回?cái)?shù)據(jù)
     *
     * @param k
     * @param v
     * @return
     */
    public V put(K k, V v) {
        if (k == null) {
            throw new IllegalArgumentException("key should not null");
        }
        /**確保容量可用,不可用擴(kuò)容**/
        ensureCapacityInternal(size + 1);

        int index = hash(k);
        Entry<K, V> entry = table[index];
        Entry<K, V> bakEntry =entry;
        if (entry == null) {
            table[index] = new Entry<K, V>(k, v, k.hashCode(), null);
            size++;
            return v;
        }
        /**頭插法**/
        while (entry != null) {
            /**已經(jīng)存在相同的key**/
            if(entry.k.equals(k)){
                entry.v=v;
                return v;
            }
            entry=entry.next;
        }
        /**不存在不相同的key**/
        table[index] = new Entry<K, V>(k, v, k.hashCode(), bakEntry);

        size++;
        return v;
    }

//  /**
//   * 擴(kuò)容重新計(jì)算存入新的table的時(shí)候用
//   *
//   * @param k
//   * @param v
//   * @param newTable
//   * @return
//   */
//  public V put(K k, V v,Entry[] newTable) {
//      if (k == null) {
//          throw new IllegalArgumentException("key should not null");
//      }
//      int index = hash(k);
//      Entry<K, V> entry = newTable[index];
//      if (entry == null) {
//          newTable[index] = new Entry<K, V>(k, v, k.hashCode(), null);
//      } else {
//          //頭插法
//          newTable[index] = new Entry<K, V>(k, v, k.hashCode(), entry);
//      }
//      size++;
//      return v;
//  }
    private void ensureCapacityInternal(int miniCapacity) {
        if (miniCapacity > expansiontThreshold) {
            /**擴(kuò)容**/
            grow(miniCapacity);
        }
    }

    /**
     * 擴(kuò)容數(shù)組
     *
     * @param miniCapacity
     */
    private void grow(int miniCapacity) {
        System.out.println("grow table----------------");
        if (miniCapacity > Integer.MAX_VALUE) {
            throw new IllegalArgumentException("capacity is max, cannot put " +
                    "any element");
        }
        int newCapacity = capacity * 2;
        if (newCapacity > Integer.MAX_VALUE) {
            newCapacity = Integer.MAX_VALUE;
        }

        this.capacity = newCapacity;
        this.expansiontThreshold = (int) (capacity * loadFactor);

        Entry[] newTable = new Entry[newCapacity];
        /**擴(kuò)容后涵但,需要將原來table中所有的值杈绸,重新計(jì)算存入新的table**/
        ReHashOriginalValue(newTable);

        this.table = newTable;

    }

    /**
     * Transfers all entries from current table to newTable.
     *
     * @param newTable
     */
    private void ReHashOriginalValue(Entry[] newTable) {
        System.out.println("Transfers all entries from current table to newTable.");
        for (Entry<K, V> e : table) {
            while (null != e) {
                Entry<K, V> next = e.next;
                int index = hash(e.getKey());
                e.next = newTable[index];
                newTable[index] = e;
                e = next;
            }
        }
    }


    /**
     * key的hashcode和數(shù)組長度取模
     *
     * @param k
     * @return
     */
    private int hash(K k) {
        int hash = k.hashCode() % this.capacity;
        return Math.abs(hash);
    }

    /**
     * 1.通過key進(jìn)行hashcode計(jì)算index
     * 2.index下表數(shù)組查詢得到Entry
     * 3.Entry==null,沒有找到value
     * 4.Entry!=null矮瘟。判斷得到的hashcode是否相等
     * 5.hashcode不相等瞳脓,判斷是否有next,next為空返回null澈侠,不存在值
     * 6.hashcode不相等劫侧,判斷是否有next,next不為空哨啃,用下一個(gè)重復(fù)5.6.7動(dòng)作
     * 7.hashcode相等烧栋,返回值
     *
     * @param k
     * @return
     */
    public V get(K k) {
        if (size == 0) {
            return null;
        } else {
            int index = hash(k);
            Entry<K, V> entry = findValue(k, table[index]);
            if (entry != null) {
                return entry.getValue();
            }
        }
        return null;
    }

    private Entry<K, V> findValue(K k, Entry<K, V> kvEntry) {
        if (kvEntry == null) {
            return null;
        }
        if (k.equals(kvEntry.getKey())) {
            return kvEntry;
        } else {
            if (kvEntry.next != null) {
                return findValue(k, kvEntry.next);
            }
        }
        return null;
    }

    public int size() {
        return this.size;
    }

    class Entry<K, V> implements Map.Entry<K, V> {
        K k;
        V v;
        int hash;
        Entry<K, V> next;

        public Entry(K k, V v, int hash, Entry<K, V> next) {
            this.k = k;
            this.v = v;
            this.hash = hash;
            this.next = next;
        }

        public K getKey() {
            return k;
        }

        public V getValue() {
            return v;
        }

    }
}

簡單測試--測試是否自動(dòng)擴(kuò)容

public class myHashMapPlusTest {
    public static void main(String[] args) {
        myHashMapPlus map = new myHashMapPlus();
        for (int i = 0; i < 1024; i++) {
            map.put(i, i);
        }
        for (int i = 0; i < 1024; i++) {
            System.out.println(map.get(i));
        }
    }
}

自動(dòng)擴(kuò)容測試結(jié)果

image.png

擴(kuò)容條件

數(shù)組長度size>ExpansiontThreshold需要擴(kuò)容,擴(kuò)容后數(shù)組的新容量為:capacity=capacity*2

擴(kuò)容后的下次再擴(kuò)容閾值為

ExpansiontThreshold=2*(capacity * DEFAULT_LOAD_FACTOR)
說明:jdk中DEFAULT_LOAD_FACTOR默認(rèn)為0.75棘催,這里沿用即可

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末劲弦,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子醇坝,更是在濱河造成了極大的恐慌邑跪,老刑警劉巖次坡,帶你破解...
    沈念sama閱讀 211,042評(píng)論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異画畅,居然都是意外死亡砸琅,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 89,996評(píng)論 2 384
  • 文/潘曉璐 我一進(jìn)店門轴踱,熙熙樓的掌柜王于貴愁眉苦臉地迎上來症脂,“玉大人,你說我怎么就攤上這事淫僻∮张瘢” “怎么了?”我有些...
    開封第一講書人閱讀 156,674評(píng)論 0 345
  • 文/不壞的土叔 我叫張陵雳灵,是天一觀的道長棕所。 經(jīng)常有香客問我,道長悯辙,這世上最難降的妖魔是什么琳省? 我笑而不...
    開封第一講書人閱讀 56,340評(píng)論 1 283
  • 正文 為了忘掉前任,我火速辦了婚禮躲撰,結(jié)果婚禮上针贬,老公的妹妹穿的比我還像新娘。我一直安慰自己拢蛋,他們只是感情好桦他,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,404評(píng)論 5 384
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著谆棱,像睡著了一般瞬铸。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上础锐,一...
    開封第一講書人閱讀 49,749評(píng)論 1 289
  • 那天嗓节,我揣著相機(jī)與錄音,去河邊找鬼皆警。 笑死拦宣,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的信姓。 我是一名探鬼主播鸵隧,決...
    沈念sama閱讀 38,902評(píng)論 3 405
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢(mèng)啊……” “哼意推!你這毒婦竟也來了豆瘫?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,662評(píng)論 0 266
  • 序言:老撾萬榮一對(duì)情侶失蹤菊值,失蹤者是張志新(化名)和其女友劉穎外驱,沒想到半個(gè)月后育灸,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,110評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡昵宇,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,451評(píng)論 2 325
  • 正文 我和宋清朗相戀三年磅崭,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片瓦哎。...
    茶點(diǎn)故事閱讀 38,577評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡砸喻,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出蒋譬,到底是詐尸還是另有隱情割岛,我是刑警寧澤,帶...
    沈念sama閱讀 34,258評(píng)論 4 328
  • 正文 年R本政府宣布犯助,位于F島的核電站蜂桶,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏也切。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,848評(píng)論 3 312
  • 文/蒙蒙 一腰湾、第九天 我趴在偏房一處隱蔽的房頂上張望雷恃。 院中可真熱鬧,春花似錦费坊、人聲如沸倒槐。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,726評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽讨越。三九已至,卻和暖如春永毅,著一層夾襖步出監(jiān)牢的瞬間把跨,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,952評(píng)論 1 264
  • 我被黑心中介騙來泰國打工沼死, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留着逐,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 46,271評(píng)論 2 360
  • 正文 我出身青樓意蛀,卻偏偏與公主長得像耸别,于是被迫代替她去往敵國和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子县钥,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,452評(píng)論 2 348

推薦閱讀更多精彩內(nèi)容

  • 一秀姐、先來復(fù)習(xí)一下我們常用的幾個(gè)方法 二、HashMap類圖結(jié)構(gòu) 三若贮、HashMap數(shù)據(jù)結(jié)構(gòu) 我們知道在Java中最...
    無量散人閱讀 743評(píng)論 0 2
  • 目錄 一.簡介 二.數(shù)據(jù)結(jié)構(gòu) 三.具體使用 四.基礎(chǔ)知識(shí) 五.源碼分析 六.源碼總結(jié) 七.與jdk1.8的區(qū)別 八...
    tyangx閱讀 158評(píng)論 0 0
  • 在看關(guān)于HashMap 1.7 BUG時(shí)省有,即多線程時(shí)會(huì)導(dǎo)致死鎖痒留。從而去查找相關(guān)資料,看看到底是什么原因造成的锥咸。 總...
    阡陌笙簫閱讀 138評(píng)論 0 0
  • 1 概述本文將從幾個(gè)常用方法下手狭瞎,來閱讀HashMap的源碼。按照從構(gòu)造方法->常用API(增搏予、刪熊锭、改、查)的順序...
    小小的coder閱讀 179評(píng)論 0 0
  • 久違的晴天雪侥,家長會(huì)碗殷。 家長大會(huì)開好到教室時(shí),離放學(xué)已經(jīng)沒多少時(shí)間了速缨。班主任說已經(jīng)安排了三個(gè)家長分享經(jīng)驗(yàn)锌妻。 放學(xué)鈴聲...
    飄雪兒5閱讀 7,513評(píng)論 16 22