LinkedHashSet
是HashSet
的一个“扩展版本”,HashSet
并不管什么顺序,不同的是LinkedHashSet
会维护“插入顺序”。HashSet
内部使用HashMap
对象来存储它的元素,而LinkedHashSet
内部使用LinkedHashMap
对象来存储和处理它的元素。这篇文章,我们将会看到LinkedHashSet
内部是如何运作的及如何维护插入顺序的。
我们首先着眼LinkedHashSet
的构造函数。在LinkedHashSet
类中一共有4个构造函数。这些构造函数都只是简单地调用父类构造函数(如HashSet
类的构造函数)。
LinkedHashSet
的构造函数是如何定义的。 //Constructor - 1 public LinkedHashSet(int initialCapacity, float loadFactor){ super(initialCapacity, loadFactor, true); //Calling super class constructor} //Constructor - 2 public LinkedHashSet(int initialCapacity){ super(initialCapacity, .75f, true); //Calling super class constructor} //Constructor - 3 public LinkedHashSet(){ super(16, .75f, true); //Calling super class constructor} //Constructor - 4 public LinkedHashSet(Collection c){ super(Math.max(2*c.size(), 11), .75f, true); //Calling super class constructor addAll(c);}
在上面的代码片段中,你可能注意到4个构造函数调用的是同一个父类的构造函数。这个构造函数(父类的,译者注)是一个包内私有构造函数(见下面的代码,HashSet的构造函数没有使用public公开,译者注),它只能被LinkedHashSet
使用。
HashSet
的其他拥有初始容量和负载因子参数的构造函数,下面是这个构造函数的定义, HashSet(int initialCapacity, float loadFactor, boolean dummy){ map = new LinkedHashMap<>(initialCapacity, loadFactor);}
显然,这个构造函数内部初始化了一个LinkedHashMap
对象,这个对象恰好被LinkedHashSet
用来存储它的元素。
LinkedHashSet
并没有自己的方法,所有的方法都继承自它的父类HashSet
,因此,对LinkedHashSet
的所有操作方式就好像对HashSet
操作一样。
HashSet
中,插入的元素是被当做HashMap
的键来保存的,而在LinkedHashSet
中被看作是LinkedHashMap
的键。这些键对应的值都是常量PRESENT
(PRESENT是HashSet的静态成员变量,译者注)。可以参考 LinkedHashSet是如何维护插入顺序的
LinkedHashSet
使用LinkedHashMap
对象来存储它的元素,插入到LinkedHashSet
中的元素实际上是被当作LinkedHashMap
的键保存起来的。
LinkedHashMap
的每一个键值对都是通过内部的静态类Entry<K, V>
实例化的。这个 Entry<K, V>
类继承了HashMap.Entry
类。这个静态类增加了两个成员变量,before
和after
来维护LinkedHasMap
元素的插入顺序。这两个成员变量分别指向前一个和后一个元素,这让LinkedHashMap
也有类似双向链表的表现。 private static class Entryextends HashMap.Entry { // These fields comprise the doubly linked list used for iteration. Entry before, after; Entry(int hash, K key, V value, HashMap.Entry next) { super(hash, key, value, next); }}
从上面代码看到的LinkedHashMap
内部类的前面两个成员变量——before
和after
负责维护LinkedHashSet
的插入顺序。LinkedHashMap
定义的成员变量header
保存的是
header
的定义就像下面这样, private transient Entryheader; //Stores the head of the doubly linked list
In LinkedHashMap, the same set of Entry objects (rather references to Entry objects) are arranged in two different manner.
One is the HashMap and another one is Doubly linked list. The Entry objects just sit on heap memory, unaware of that they are part of two different data structures.接下来看一个例子就知道LinkedHashSet
内部是如何工作的了。
public class LinkedHashSetExample{ public static void main(String[] args) { //Creating LinkedHashSet LinkedHashSetset = new LinkedHashSet (); //Adding elements to LinkedHashSet set.add("BLUE"); set.add("RED"); set.add("GREEN"); set.add("BLACK"); }}
下面的图片展示了这个程序是如何运行的。
如果你知道LinkedHashMap
内部是如何工作的,就非常容易明白LinkedHashSet
内部是如何工作的。看一遍LinkedHashSet
和LinkedHashMap
的源码,你就能够准确地理解在Java中LinkedHashSet
内部是如何工作的。 原文链接: