HashMap

HashMap是基于动态数组和单向链表实现的,具体是怎么实现的呢,我们来看源码

public HashMap() {
    table = (HashMapEntry<K, V>[]) EMPTY_TABLE;
    threshold = -1; // Forces first put invocation to replace EMPTY_TABLE
}

首先,在构造方法中会创建一个默认大小为2存储对象为HashMapEntry的table数组

 private static final Entry[] EMPTY_TABLE
     = new HashMapEntry[MINIMUM_CAPACITY >>> 1];

这个HashMapEntry又是什么呢,它保存有4个参数

HashMapEntry(K key, V value, int hash, HashMapEntry<K, V> next) {
   this.key = key;
   this.value = value;
   this.hash = hash;
   this.next = next;
}

先了解到这,我们来看看put方法是怎么实现的

@Override 
public V put(K key, V value) {
    if (key == null) {
        return putValueForNullKey(value);
    }

    int hash = Collections.secondaryHash(key);
    HashMapEntry<K, V>[] tab = table;
    int index = hash & (tab.length - 1);
    for (HashMapEntry<K, V> e = tab[index]; e != null; e = e.next) {
         if (e.hash == hash && key.equals(e.key)) {
             preModify(e);
             V oldValue = e.value;
             e.value = value;
             return oldValue;
        }
    }

    // No entry for (non-null) key is present; create one
    modCount++;
    if (size++ > threshold) {
        tab = doubleCapacity();
        index = hash & (tab.length - 1);
    }
    addNewEntry(key, value, hash, index);
    return null;
}

首先,判断key值是否为空,如果为空,则用一个entryForNullKey对象来存储相应数据

private V putValueForNullKey(V value) {
     HashMapEntry<K, V> entry = entryForNullKey;
     if (entry == null) {
         addNewEntryForNullKey(value);
         size++;
         modCount++;
         return null;
     } else {
         preModify(entry);
         V oldValue = entry.value;
         entry.value = value;
         return oldValue;
    }
}
void addNewEntryForNullKey(V value) {
    entryForNullKey = new HashMapEntry<K, V>(null, value, 0, null);
}

else方法是对已有key为null的数据更新,preModify不用管,在HashMap中并无具体实现

继续往下看,我们先跳过for方法,回头再来看,doubleCapacity是对数组扩容的,也就不看了,直接来看addNewEntry方法

void addNewEntry(K key, V value, int hash, int index) {
    table[index] = new HashMapEntry<K, V>(key, value, hash, table[index]);
}

这边就是往数组中插入,并将原先位置的数据作为新数据的next变量,举个例子:
put("1","1"),put("qa","2s"),put两个数据,假设这两次的index值获取到的都为0,会怎么处理呢?首先第一次put时,table[0]会直接存相应数据,当第二次put时,table[0]的值就更新为第二次的数据,原先的table[0]会作为现在table[0]的next参数,形成单向链表存储,以后若还有indexi为0的数据过来,则继续按照这种规则规则存储。

再来看看for方法,先判断这个index是否存在数据,不存在则addNewEntry,若存在,则找到这个数据,判断key值和hash值是否相等,若相等,说明是要更新数据,若不等,则需要找到链表的下一个值,再次判断,周而复始。若最终链表循环结束,还是未找到,则走addNewEntry方法,这样就又跟举的例子一样的处理步骤了。

至于HashMap是无序的,那又是为什么呢?

一次主要因为这个index值,put的数据可能会存在table的任何位置上,而读取时是按照从小到大依次读取的,我们来看看读取的源码

HashMapEntry<K, V> nextEntry() {
     if (modCount != expectedModCount)
         throw new ConcurrentModificationException();
         if (nextEntry == null)
         throw new NoSuchElementException();

         HashMapEntry<K, V> entryToReturn = nextEntry;
         HashMapEntry<K, V>[] tab = table;
         HashMapEntry<K, V> next = entryToReturn.next;
         while (next == null && nextIndex < tab.length) {
             next = tab[nextIndex++];
        }
        nextEntry = next;
        return lastEntryReturned = entryToReturn;
}

看while方法,只有当next的值为空,即链表索引都结束了,tab的nextIndex才会加1,再继续找当前链表中的值,所以导致打印出来的所有key的顺序并不跟插入的一致

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,293评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,604评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,958评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,729评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,719评论 5 366
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,630评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,000评论 3 397
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,665评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,909评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,646评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,726评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,400评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,986评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,959评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,197评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,996评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,481评论 2 342

推荐阅读更多精彩内容

  • HashMap 是 Java 面试必考的知识点,面试官从这个小知识点就可以了解我们对 Java 基础的掌握程度。网...
    野狗子嗷嗷嗷阅读 6,650评论 9 107
  • 前言 这次我和大家一起学习HashMap,HashMap我们在工作中经常会使用,而且面试中也很频繁会问到,因为它里...
    liangzzz阅读 7,965评论 7 102
  • 实际上,HashSet 和 HashMap 之间有很多相似之处,对于 HashSet 而言,系统采用 Hash 算...
    曹振华阅读 2,508评论 1 37
  • 情绪和情绪之间,会互相转化,互相掩盖,情绪和情绪之间会层层叠叠地交织在一起。当人们担心自己的某个情绪或情感不被允许...
    清水微甜的日常阅读 204评论 0 0
  • 听一首舒缓的歌曲,让自己的心平静下来;品一杯淡茶,让自己的心沉稳下来;来一次深呼吸,让自己心里的闷气排出来;读一本...
    雪后山阅读 357评论 1 11