Map篇暂告段落,却并非离我们而去。这不在本篇中你就能经常见到她。HashSet、LinkedHashSet、TreeSet各自基于对应Map实现,各自源码内容较少,因此归纳为一篇。
HashSet
|
|
HashSet基于HashMap实现;而Map是键值对形式的,因此构造一个PRESENT假装为值。
同样在HashSet源码的Line273与Line294分别见看到老朋友writeObject()和readObject()。使用它们自定义序列化规则,将不会调用默认的序列化方法。
这样做可以降低性能消耗的同时,还可以减少序列化字节流的大小,从而减少网络开销(RPC框架中)。[①]
记得在之前的文章中留了一个问题。即该private方法供谁调用?解释如下,然而笔者并未在ObjectOutputStream源码中找到getPrivateMethod方法,不知是否由于版本不同还是作者笔误。倒是在ObjectStreamClass中找到了getPrivateMethod()。
ObjectOutputStream使用了反射来寻找是否声明了这两个方法。因为ObjectOutputStream使用getPrivateMethod,所以这些方法不得不被声明为priate以至于供ObjectOutputStream来使用。 [②]
|
|
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呢?
|
|
LinkedHashSet
|
|
增加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在实际项目中的应用,感兴趣的同学可以深入学习。