摘要:同樣在源碼的與分別見看到老朋友和。這樣做可以降低性能消耗的同時,還可以減少序列化字節流的大小,從而減少網絡開銷框架中。使用了反射來尋找是否聲明了這兩個方法。十進制和,通過返回值能反應當前狀態。
Map篇暫告段落,卻并非離我們而去。這不在本篇中你就能經常見到她。HashSet、LinkedHashSet、TreeSet各自基于對應Map實現,各自源碼內容較少,因此歸納為一篇。
HashSet// Dummy value to associate with an Object in the backing Map private static final Object PRESENT = new Object();
HashSet基于HashMap實現;而Map是鍵值對形式的,因此構造一個PRESENT假裝為值。
同樣在HashSet源碼的Line273與Line294分別見看到老朋友writeObject()和readObject()。使用它們自定義序列化規則,將不會調用默認的序列化方法。
這樣做可以降低性能消耗的同時,還可以減少序列化字節流的大小,從而減少網絡開銷(RPC框架中)。[①]
記得在之前的文章中留了一個問題。即該private方法供誰調用?解釋如下,然而筆者并未在ObjectOutputStream源碼中找到getPrivateMethod方法,不知是否由于版本不同還是作者筆誤。倒是在ObjectStreamClass中找到了getPrivateMethod()。
ObjectOutputStream使用了反射來尋找是否聲明了這兩個方法。因為ObjectOutputStream使用getPrivateMethod,所以這些方法不得不被聲明為priate以至于供ObjectOutputStream來使用。 [②]
/** * Creates a late-binding * and fail-fast {@link Spliterator} over the elements in this * set. * *The {@code Spliterator} reports {@link Spliterator#SIZED} and * {@link Spliterator#DISTINCT}. Overriding implementations should document * the reporting of additional characteristic values. * * @return a {@code Spliterator} over the elements in this set * @since 1.8 */ public Spliterator
spliterator() { return new HashMap.KeySpliterator (map, 0, -1, 0, 0); } // HashMap源碼中 static final class KeySpliterator extends HashMapSpliterator implements Spliterator { KeySpliterator(HashMap m, int origin, int fence, int est, int expectedModCount) { super(m, origin, fence, est, expectedModCount); } public KeySpliterator trySplit() { int hi = getFence(), lo = index, mid = (lo + hi) >>> 1; return (lo >= mid || current != null) ? null : new KeySpliterator<>(map, lo, index = mid, est >>>= 1, expectedModCount); } public void forEachRemaining(Consumer super K> action) { int i, hi, mc; if (action == null) throw new NullPointerException(); HashMap m = map; Node [] tab = m.table; if ((hi = fence) < 0) { mc = expectedModCount = m.modCount; hi = fence = (tab == null) ? 0 : tab.length; } else mc = expectedModCount; if (tab != null && tab.length >= hi && (i = index) >= 0 && (i < (index = hi) || current != null)) { Node p = current; current = null; do { if (p == null) p = tab[i++]; else { action.accept(p.key); p = p.next; } } while (p != null || i < hi); if (m.modCount != mc) throw new ConcurrentModificationException(); } } public boolean tryAdvance(Consumer super K> action) { int hi; if (action == null) throw new NullPointerException(); Node [] tab = map.table; if (tab != null && tab.length >= (hi = getFence()) && index >= 0) { while (current != null || index < hi) { if (current == null) current = tab[index++]; else { K k = current.key; current = current.next; action.accept(k); if (map.modCount != expectedModCount) throw new ConcurrentModificationException(); return true; } } } return false; } public int characteristics() { return (fence < 0 || est == map.size ? Spliterator.SIZED : 0) | Spliterator.DISTINCT; } }
spliterator()將Set中所有元素封裝中并返回,依靠HashMap.KeySpliterator()方法來實現。HashMap.KeySpliterator重寫了Spliterator接口的一些方法:
tryAdvance:如果存在沒處理(action.accept(k))的數據,執行指定的代碼并返回true;若不存在,直接返回false;單次;
forEachRemaining:循環對所有數據進行處理(action.accept(p.key));
trySplit:分割出一個新的Spliterator,從“mid = (lo + hi) >>> 1;”來看,KeySpliterator是對半切割的。
characteristics:返回特征值。這里只會有2種結果。Spliterator.SIZED(0x00000040)|Spliterator.DISTINCT(0x00000001)=65(十進制)和0|Spliterator.DISTINCT(0x00000001)=1,通過返回值能反應KeySpliterator當前狀態。因為一旦調用以上方法處理數據,fence值就會被改變,即從65變為1(個人理解,網上資料鳳毛麟角)。
“jdk1.8中的集合框架中的數據結構都默認實現了Spliterator。”(慚愧的是當時在看HashMap并沒有注意到,由于Set代碼行數少,反倒引起了關注。)看看下面的執行結果你是否能全部bingo呢?
HashSet hs = new HashSet(); hs.add("c"); hs.add("h"); hs.add("e"); SpliteratorLinkedHashSetspliterator = hs.spliterator(); System.out.println("characteristics:"+spliterator.characteristics()); Spliterator spliterator2 = spliterator.trySplit(); while(spliterator.tryAdvance(t -> System.out.println("tryAdvance:"+t.toString()))); while(spliterator2.tryAdvance(t -> System.out.println("trySplit:"+t.toString()))); System.out.println("characteristics:"+spliterator.characteristics()); hs.spliterator().forEachRemaining(t -> System.out.println("forEachRemaining:"+t.toString()));
/** * Constructs a new, empty linked hash set. (This package private * constructor is only used by LinkedHashSet.) The backing * HashMap instance is a LinkedHashMap with the specified initial * capacity and the specified load factor. * * @param initialCapacity the initial capacity of the hash map * @param loadFactor the load factor of the hash map * @param dummy ignored (distinguishes this * constructor from other int, float constructor.) * @throws IllegalArgumentException if the initial capacity is less * than zero, or if the load factor is nonpositive */ HashSet(int initialCapacity, float loadFactor, boolean dummy) { map = new LinkedHashMap<>(initialCapacity, loadFactor); }
增加dummy標志與HashSet(int initialCapacity, float loadFactor, boolean dummy)構造方法區分開來,供LinkedHashSet調用。
TreeSet略。(是不是有種翻閱課后答案參考書的感覺- -)
說點什么:HashSet無序;允許值為null;非線程安全;底層增刪等操作基于HashMap實現;
LinkedHashSet有序;允許值為null;非線程安全;依賴于HashSet,底層增刪等操作基于LinkedHashMap實現;
TreeSet有序;不允許為null;非線程安全;底層增刪等操作基于TreeMap實現。
從查閱Spliterator相關資料的感受就是J8的一些技術點在國內應用貌似還不是那么普及。③中舉了25個java.util.Spliterators在實際項目中的應用,感興趣的同學可以深入學習。
更多有意思的內容,歡迎訪問筆者小站: rebey.cn
知識點:① java序列化用法以及理論(三);
② 什么是writeObject 和readObject?可定制的序列化過程【譯】;
③ Java Code Examples for java.util.Spliterators;
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/71136.html
摘要:下面總結一下集合常用的三個子類吧無序,允許為,底層是散列表紅黑樹,非線程同步有序,不允許為,底層是紅黑樹非線程同步迭代有序,允許為,底層是雙向鏈表,非線程同步從結論而言我們就可以根據自己的實際情況來使用了。 前言 聲明,本文用的是jdk1.8 前面章節回顧: Collection總覽 List集合就這么簡單【源碼剖析】 Map集合、散列表、紅黑樹介紹 HashMap就是這么簡單【源碼...
摘要:并把最終的隨機數輸出到控制臺。方法,在集合中如何存儲元素取決于方法的返回值返回,集合中只有一個元素。創建集合對象,傳入比較器。 1_HashSet存儲字符串并遍歷 A:Set集合概述及特點 通過API查看即可 B:案例演示 HashSet存儲字符串并遍歷 import java.util.HashSet; public class Demo1_HashSet { p...
摘要:集合判斷兩個元素的標準是兩個對象通過方法比較相等,并且兩個對象的方法返回值也相等。的集合元素也是有序的,以枚舉值在類內的定義順序來決定集合元素的順序。是所有實現類中性能最好的,但它只能保存同一個枚舉類的枚舉值作為集合元素。 Set集合通常不能記住元素的添加順序。Set不允許包含重復的元素。 Set集合不允許包含相同的元素,如果試圖把兩個相同的元素加入同一個Set集合中,則添加操作...
摘要:當復制集合中的所有元素來創建新的集合時,要求集合中的所有元素必須是同一個枚舉類的枚舉值各實現類的性能分析的性能總比好,特別是最常用的添加查詢元素等操作。因為需要額外的紅黑樹算法來維護集合元素的次序。在創建時進行,以防對集合的意外非同步訪問 HashSet 大多時候使用Set集合時就是使用HashSet實現類。HashSet按Hash算法來存儲集合中的元素,因此具有很好的存取和查找性能 ...
閱讀 2863·2021-10-14 09:42
閱讀 3182·2019-08-30 15:52
閱讀 3267·2019-08-30 14:02
閱讀 1113·2019-08-29 15:42
閱讀 538·2019-08-29 13:20
閱讀 1164·2019-08-29 12:24
閱讀 486·2019-08-26 10:20
閱讀 686·2019-08-23 18:31