1. 程式人生 > >jdk1.8中HashMap是如何維護EntrySet的

jdk1.8中HashMap是如何維護EntrySet的

如果大家分析過hashmap的原始碼,就會發現HashMap維護EntrySet的方式是比較特別的。有的人會疑問,jdk1.8中HashMap到底是如何維護EntrySet的。一般來說,我們實現EntrySet就是在put值的時候將其順便加到EntrySet即可。但是jdk1.8中並沒有這樣做。

put函式的原始碼:

final V putVal(int hash, K key, V value, boolean onlyIfAbsent,
                   boolean evict) {
        Node<K,V>[] tab; Node<K,V> p; int
n, i; if ((tab = table) == null || (n = tab.length) == 0) n = (tab = resize()).length; if ((p = tab[i = (n - 1) & hash]) == null) tab[i] = newNode(hash, key, value, null); else { Node<K,V> e; K k; if (p.hash == hash && ((k = p.key) == key || (key != null
&& key.equals(k)))) e = p; else if (p instanceof TreeNode) e = ((TreeNode<K,V>)p).putTreeVal(this, tab, hash, key, value); else { for (int binCount = 0; ; ++binCount) { if ((e = p.next) == null) { p.next = newNode(hash, key, value
, null); if (binCount >= TREEIFY_THRESHOLD - 1) // -1 for 1st treeifyBin(tab, hash); break; } if (e.hash == hash && ((k = e.key) == key || (key != null && key.equals(k)))) break; p = e; } } if (e != null) { // existing mapping for key V oldValue = e.value; if (!onlyIfAbsent || oldValue == null) e.value = value; afterNodeAccess(e); return oldValue; } } ++modCount; if (++size > threshold) resize(); afterNodeInsertion(evict); return null; }

可以看到,這段程式碼中並沒有一絲維護EntrySet的跡象。

那麼平時我們遍歷Map的時候獲取EntrySet是怎麼來的呢?
我們可以看看EntrySet方法的原始碼:

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

可以看到,就直接返回了一個entrySet,那麼這個entrySet是什麼呢?

transient Set<Map.Entry<K,V>> entrySet;

我們不難看到,整個過程中,就直接返回了entrySet,我們在put 的時候也看不到jdk將put的元素加入到entrySet中,那我們遍歷的時候元素哪裡來?

我們可以看到,雖然是返回的entrySet,但是事實上你在輸出(System.out.println)entrySet的時候,是會呼叫toString()的,我們看看toString方法的原始碼:

public String toString() {
        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(' ');
        }
    }

可以看到,原來jdk使用了懶載入的方式。其中iterator就會獲取hashMap裡面的元素了。

相關推薦

jdk1.8HashMap是如何維護EntrySet

如果大家分析過hashmap的原始碼,就會發現HashMap維護EntrySet的方式是比較特別的。有的人會疑問,jdk1.8中HashMap到底是如何維護EntrySet的。一般來說,我們實現EntrySet就是在put值的時候將其順便加到EntrySet即可

JDK1.8HashMap實現

替換 應該 初始化 第一個元素 擴容 實現 1.8 put 相同 JDK1.8中的HashMap實現跟JDK1.7中的實現有很大差別。下面分析JDK1.8中的實現,主要看put和get方法。 構造方法的時候並沒有初始化,而是在第一次put的時候初始化 put

1.jdk1.8hashMap的原理,hash衝突如何解決

一:hashMap的工作原理        HashMap是基於鏈地址法的原理,使用put(key, value)儲存物件到HashMap中,使用get(key)從HashMap中獲取物件。        當我們給put()方法傳遞鍵和值時,我們先對鍵呼叫hashCode

通俗易懂的JDK1.8HashMap原始碼分析(歡迎探討指正)+ 典型面試題

面試題在最下面 說到HashMap之前,閱讀ArrayList與LinkedList的原始碼後做個總結 ArrayList 底層是陣列,查詢效率高,增刪效率低 LinkedList底層是雙鏈表,查詢效率低,增刪效率高   這裡只是總結看完原始碼後對hashm

JAVA筆記 —— JDK1.8 HashMap 的變化

HashMap(1.8) 1、資料結構的變化:紅黑樹   JDK1.8之前,HashMap的資料結構:陣列 + 連結串列(單鏈表)   JDK1.8之後,HashMap的資料結構:陣列 + 連結串列 + 紅黑樹   JDK1.8之前,HashMap採用陣列+連結串

JDK1.7和1.8HashMap與ConcurrentHashMap總結比較

談到HashMap和ConcurrentHashMap,必然會聯想到一些其他集合結構,比如HashTable,Vector等,先理一下他們的區別吧。其實HashTable和Vector已經被廢棄了,HashTable和Vector以及ConcurrentHashMap都是執行緒安全的同步結構,區別是

JDK1.8 hashmap和concurrentHashMap

hashmap 在JDK1.6中,HashMap採用Node陣列+連結串列實現,即使用連結串列處理衝突,同一hash值的連結串列都儲存在一個連結串列裡。但是當位於一個桶中的元素較多,即hash值相等的元素較多時,通過key值依次查詢的效率較低。而JDK1.8中

HashMapJDK1.8的實現

摘要HashMap是Java程式設計師使用頻率最高的用於對映(鍵值對)處理的資料型別。隨著JDK(Java Developmet Kit)版本的更新,JDK1.8對HashMap底層的實現進行了優化,例如引入紅黑樹的資料結構和擴容的優化等。本文結合JDK1.7和JDK1.8的區別,深入探討HashMap的結構

JDK1.7HashMap死環問題及JDK1.8HashMap的優化原始碼詳解

一、JDK1.7中HashMap擴容死鎖問題 我們首先來看一下JDK1.7中put方法的原始碼 我們開啟addEntry方法如下,它會判斷陣列當前容量是否已經超過的閾值,例如假設當前的陣列容量是16,載入因子為0.75,即超過了12,並且剛好要插入的索引處有元素,這時候就需要進行擴容操作,可以看到resi

jdk1.8接口可以寫默認方法

wheel void JD PE 靜態 調用 默認 sta default interface Vehicle {  default void print(){     System.out.println("我是一輛車!");   }   stat

Java7、8HashMap和ConcurrentHashMap原始碼閱讀

首先來看下HashMap的類繼承結構: public class HashMap extends AbstractMap<K,V> impement Map<K,V>,Coloneable,Serializable{ } 可以看出HashMap實現了Map介面。其裡面的方法都是

Java7、8HashMap和ConcurrentHashMap源碼閱讀

動態擴容 nal das pub end flat 數據 算數 ext 首先來看下HashMap的類繼承結構: public class HashMap extends AbstractMap<K,V> impement Map<K,V>,Colon

java 7/ 8 HashMap 及 concurrentHashMap

前言:      HashMap 不支援併發操作,而concurrentHashMap 支援併發操作,本文簡單介紹Java 7 、Java8 中HashMap 及 concurrentHashMap 底層實現。 1、Java 7 中  HashMap

JDK1.8TreeMap原始碼解析——紅黑樹刪除

在看本文之前建議先看一下二叉樹的刪除過程,這裡有一篇文章寫得不錯,可以看一下 1、後繼節點 在看原始碼之前,先說說紅黑樹尋找 待刪除節點t 的 後繼節點 的過程: 如果待刪除節點t有右節點,那麼後繼節點為該節點右子樹中最左的節點,也就是右子樹中值最小的節

Java7/8 HashMap 和 ConcurrentHashMap的對比和分析

網上關於 HashMap 和 ConcurrentHashMap 的文章確實不少,不過缺斤少兩的文章比較多,所以才想自己也寫一篇,把細節說清楚說透,尤其像 Java8 中的 ConcurrentHashMap,大部分文章都說不清楚。終歸是希望能降低大家學習的成本,不希望大家到處找各種不是很靠譜的文章,看完一篇

jdk1.8computeIfAbsent方法用法

computeIfAbsent(K key, Function《? super K, ? extends V> mappingFunction) computeIfAbsent的方法有兩個引數 第一個是所選map的key,第二個是需要做的操作。這個方法當key值不存在

Java 8HashMap和LinkedHashMap如何解決衝突

什麼時候會產生衝突?? HashMap中呼叫hashCode()方法來計算hashCode。 由於在Java中兩個不同的物件可能有一樣的hashCode,所以不同的鍵可能有一樣hashCode,從而導致衝突的產生。 解決: 在Java 8 之前,HashMap和其他基於map

ConcurrentHashMap JDK1.8結構原理及原始碼分析

注:本文根據網路和部分書籍整理基於JDK1.7書寫,如有雷同敬請諒解  歡迎指正文中的錯誤之處。 資料結構       ConcurrentHashMap 1.8 拋棄了Segment分段鎖機制,採用Node + CAS + Synchronized來保證併發安全進行實現

JDK1.8介面和抽象類

public abstract class Person { // 1,可以定義成員變數 //2, 可以是任意許可權修飾符 private int a = 1; protected int b =1; public int c = 1; //3,

【轉】Java 8HashMap和LinkedHashMap如何解決衝突

原文來自一個java大牛的部落格 原文地址http://javarevisited.blogspot.jp/2016/01/how-does-java-hashmap-or-linkedhahsmap-handles.html 部落格講解了Java 8中HashMap和LinkedH