遍歷 Map 中 EntrySet 集合一點思考。

按照下面的代碼去遍歷 Map 集合,可以獲取到存入到 Map 的所有數(shù)據(jù)屈呕,這樣是沒有任何問題的,但是深入源碼卻發(fā)現(xiàn)有點問題:

Iterator<Map.Entry<String, String>> iterator = map.entrySet().iterator();
while (iterator.hasNext()) {
    Map.Entry<String, String> next = iterator.next();
    String key = next.getKey();
    String value = next.getValue();
    System.out.println("key = "+key+";value = "+value);
}

1棺亭、遍歷的源碼分析

HashMap.entrySet() 是獲取 HashMap 封裝了 key-value 的 Map.Entry 所有對象虎眨。

public Set<Map.Entry<K,V>> entrySet() {
    return entrySet0();
}

內(nèi)部調(diào)用了 entrySet0() 方法

private Set<Map.Entry<K,V>> entrySet0() {
    Set<Map.Entry<K,V>> es = entrySet;
    return es != null ? es : (entrySet = new EntrySet());
}

EntrySet 的源碼

private final class EntrySet extends AbstractSet<Map.Entry<K,V>> {
    public Iterator<Map.Entry<K,V>> iterator() {
        return newEntryIterator();
    }
    public boolean contains(Object o) {
        if (!(o instanceof Map.Entry))
            return false;
        Map.Entry<K,V> e = (Map.Entry<K,V>) o;
        Entry<K,V> candidate = getEntry(e.getKey());
        return candidate != null && candidate.equals(e);
    }
    public boolean remove(Object o) {
        return removeMapping(o) != null;
    }
    public int size() {
        return size;
    }
    public void clear() {
        HashMap.this.clear();
    }
    public final Spliterator<Map.Entry<K,V>> spliterator() {
        return new EntrySpliterator<>(HashMap.this, 0, -1, 0, 0);
    }
    public final void forEach(Consumer<? super Map.Entry<K,V>> action) {
        HashMapEntry<K,V>[] tab;
        if (action == null)
            throw new NullPointerException();
        if (size > 0 && (tab = table) != null) {
            int mc = modCount;
            for (int i = 0; i < tab.length; ++i) {
                for (HashMapEntry<K,V> e = tab[i]; e != null; e = e.next) {
                    action.accept(e);
                    // Android-modified - this was outside of the loop, inconsistent with other
                    // collections
                    if (modCount != mc) {
                        throw new ConcurrentModificationException();
                    }
                }
            }
        }
    }
}

從上面的調(diào)用關(guān)系來看,最后返回一個 EntrySet 對象而已,EntrySet 是無參構(gòu)造實例化的嗽桩,查看源碼它并沒有顯示的提供無參構(gòu)造钟鸵,也就是說沒有做什么操作,只是把 EntrySet 對象返回而已涤躲。
那我們在調(diào)用 map.entrySet() 處打斷點發(fā)現(xiàn)棺耍,EntrySet 內(nèi)部卻是有值的,這就奇怪的种樱,這些值是哪來的蒙袍,它并沒有操作存儲數(shù)據(jù)的 table 數(shù)組啊,那怎么會有數(shù)據(jù)呢嫩挤?

下面是斷點的圖解:

這里寫圖片描述

2害幅、在對某個對象進行 add to watch 實際上調(diào)用該對象的 toString 方法。

下面的測試例子

class T {
    private String name;
    public T() {
    }
    //測試斷點的情況下是否會調(diào)用 toString() 方法
    @Override
    public String toString() {
        this.name = "abc";
        System.out.println("輸出了:" + name);
        return super.toString();
    }
}

main()方法
System.out.println("start");
T t = new T();
System.out.println("end");

沒有斷點的情況的輸出結(jié)果:
System.out: start
System.out: end

斷點的情況的輸出結(jié)果:
System.out: start
System.out: 輸出了:abc
System.out: end

在這里可以得出結(jié)論就是對一個對象打斷點會執(zhí)行該對象的 toString() 方法岂昭。同理在我們給 entries 打斷點時可以看的返回的 EntrySet 集合是有數(shù)據(jù)的以现,可以知道這個數(shù)據(jù)肯定就是在 EntrySet 中的 toString() 方法獲取的,查閱源碼可以知道约啊, EntrySet 并沒有實現(xiàn) toString 方法邑遏,而是在祖父類 AbstractCollection 實現(xiàn)了,代碼如下:

public String toString() {
    //實際上就是獲取 Iterator 對象恰矩,然后不斷地調(diào)用 next() 方法而得到的值记盒。
    Iterator<E> it = iterator();
    if (! it.hasNext())
        return "[]";
    StringBuilder sb = new StringBuilder();
    sb.append('[');
    for (;;) {
        E e = it.next();
        sb.append(e == this ? "(this Collection)" : e);
        if (! it.hasNext())
            return sb.append(']').toString();
        sb.append(',').append(' ');
    }
}

若是不明在其中的調(diào)用關(guān)系可以查閱我之前的博客 LinkedHashMap 是如何能作為最近最少使用算法底層數(shù)據(jù)結(jié)構(gòu)的?

這里寫圖片描述

結(jié)論:在獲取 EntrySet 之后外傅,我們一般調(diào)用 iterator() 獲取 Iterator 對象纪吮,然后不斷的調(diào)用 next() 方法,實際上這個才是真正獲取數(shù)據(jù)的地方萎胰。它內(nèi)部遍歷 table 數(shù)組來獲取指定的數(shù)據(jù)碾盟。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市技竟,隨后出現(xiàn)的幾起案子冰肴,更是在濱河造成了極大的恐慌,老刑警劉巖灵奖,帶你破解...
    沈念sama閱讀 218,546評論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件嚼沿,死亡現(xiàn)場離奇詭異估盘,居然都是意外死亡瓷患,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,224評論 3 395
  • 文/潘曉璐 我一進店門遣妥,熙熙樓的掌柜王于貴愁眉苦臉地迎上來擅编,“玉大人,你說我怎么就攤上這事“” “怎么了谭贪?”我有些...
    開封第一講書人閱讀 164,911評論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長锦担。 經(jīng)常有香客問我俭识,道長,這世上最難降的妖魔是什么洞渔? 我笑而不...
    開封第一講書人閱讀 58,737評論 1 294
  • 正文 為了忘掉前任套媚,我火速辦了婚禮,結(jié)果婚禮上磁椒,老公的妹妹穿的比我還像新娘堤瘤。我一直安慰自己,他們只是感情好浆熔,可當我...
    茶點故事閱讀 67,753評論 6 392
  • 文/花漫 我一把揭開白布本辐。 她就那樣靜靜地躺著,像睡著了一般医增。 火紅的嫁衣襯著肌膚如雪慎皱。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,598評論 1 305
  • 那天叶骨,我揣著相機與錄音宝冕,去河邊找鬼。 笑死邓萨,一個胖子當著我的面吹牛地梨,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播缔恳,決...
    沈念sama閱讀 40,338評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼宝剖,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了歉甚?” 一聲冷哼從身側(cè)響起万细,我...
    開封第一講書人閱讀 39,249評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎纸泄,沒想到半個月后赖钞,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,696評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡聘裁,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,888評論 3 336
  • 正文 我和宋清朗相戀三年雪营,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片衡便。...
    茶點故事閱讀 40,013評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡献起,死狀恐怖洋访,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情谴餐,我是刑警寧澤姻政,帶...
    沈念sama閱讀 35,731評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站岂嗓,受9級特大地震影響汁展,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜厌殉,卻給世界環(huán)境...
    茶點故事閱讀 41,348評論 3 330
  • 文/蒙蒙 一善镰、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧年枕,春花似錦炫欺、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,929評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至摩桶,卻和暖如春桥状,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背硝清。 一陣腳步聲響...
    開封第一講書人閱讀 33,048評論 1 270
  • 我被黑心中介騙來泰國打工辅斟, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人芦拿。 一個月前我還...
    沈念sama閱讀 48,203評論 3 370
  • 正文 我出身青樓士飒,卻偏偏與公主長得像,于是被迫代替她去往敵國和親蔗崎。 傳聞我的和親對象是個殘疾皇子酵幕,可洞房花燭夜當晚...
    茶點故事閱讀 44,960評論 2 355

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

  • 1. Java基礎(chǔ)部分 基礎(chǔ)部分的順序:基本語法,類相關(guān)的語法缓苛,內(nèi)部類的語法芳撒,繼承相關(guān)的語法,異常的語法未桥,線程的語...
    子非魚_t_閱讀 31,638評論 18 399
  • java筆記第一天 == 和 equals ==比較的比較的是兩個變量的值是否相等笔刹,對于引用型變量表示的是兩個變量...
    jmychou閱讀 1,500評論 0 3
  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理,服務(wù)發(fā)現(xiàn)冬耿,斷路器舌菜,智...
    卡卡羅2017閱讀 134,657評論 18 139
  • 傳送門 解讀阿里Java開發(fā)手冊(v1.1.1) - 異常日志 前言 阿里Java開發(fā)手冊談不上圣經(jīng),但確實是大量...
    kelgon閱讀 4,366評論 4 50
  • nginx編譯 wget http://nginx.org/download/nginx-1.9.12.tar.g...
    gakaki閱讀 1,826評論 0 51