HashSet vs LinkedHashSet

他们有什么区别? 我知道

LinkedHashSet是HashSet的有序版本,它在所有元素之间维护一个双向链表。 当您关心迭代顺序时,请使用此类而不是HashSet。 在迭代HashSet时,顺序是不可预知的,而LinkedHashSet允许您按照插入顺序遍历元素。

但是在LinkedHashSet的源代码中只有调用HashSet的构造函数。 那么双链表和插入顺序在哪里呢?

答案在于LinkedHashSet用于构造基类的构造函数:

 public LinkedHashSet(int initialCapacity, float loadFactor) { super(initialCapacity, loadFactor, true); // <-- boolean dummy argument } ... public LinkedHashSet(int initialCapacity) { super(initialCapacity, .75f, true); // <-- boolean dummy argument } ... public LinkedHashSet() { super(16, .75f, true); // <-- boolean dummy argument } ... public LinkedHashSet(Collection<? extends E> c) { super(Math.max(2*c.size(), 11), .75f, true); // <-- boolean dummy argument addAll(c); } 

并且描述一个带有布尔参数的HashSet构造函数的例子,如下所示:

 /** * 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<E,Object>(initialCapacity, loadFactor); } 

LinkedHashSet的构造函数调用以下基类构造函数:

 HashSet(int initialCapacity, float loadFactor, boolean dummy) { map = new LinkedHashMap<E, Object>(initialCapacity, loadFactor); } 

正如你所看到的,内部映射是一个LinkedHashMap 。 如果您查看LinkedHashMap内部,您将发现以下字段:

 private transient Entry<K, V> header; 

这是有问题的链表。

你应该看看它调用的HashSet构造函数的源代码…这是一个特殊的构造函数,它使后端Map一个LinkedHashMap而不仅仅是一个HashMap

HashSet是无序的和未sorting的Set。 LinkedHashSet是HashSet的有序版本.HashSet和LinkedHashSet的唯一区别是LinkedHashSet维护了插入顺序。 当我们遍历一个HashSet时,顺序是不可预知的,而在LinkedHashSet的情况下它是可预测的。 LinkedHashSet维护插入顺序的原因是因为底层数据结构是一个双向链表。

HashSet:实际上是无序的。 如果你传递参数的意思

 Set<Integer> set=new HashSet<Integer>(); for(int i=0;i<set.length;i++) { SOP(set)`enter code here` } 

输出:可能是2,1,3不可预测的。 下次再下单。

生成FIFO顺序的LinkedHashSet()

我build议大部分时间使用LinkedHashSet ,因为它总体上具有更好的性能 ):

  1. 可预测的 迭代顺序LinkedHashSet(Oracle)
  2. LinkedHashSet比HashSet更昂贵的插入;
  3. 一般来说,性能比HashMap稍好一些,因为大部分时间我们都使用Set结构进行迭代。

性能testing:

 ------------- TreeSet ------------- size add contains iterate 10 746 173 89 100 501 264 68 1000 714 410 69 10000 1975 552 69 ------------- HashSet ------------- size add contains iterate 10 308 91 94 100 178 75 73 1000 216 110 72 10000 711 215 100 ---------- LinkedHashSet ---------- size add contains iterate 10 350 65 83 100 270 74 55 1000 303 111 54 10000 1615 256 58 

您可以在这里看到源testing页面: 最终性能testing示例

如果您看一下LinkedHashSet类中调用的构造函数,您将在内部看到它是一个用于支持目的的LinkedHashMap

所有的方法和构造函数是相同的,但只有一个区别是LinkedHashset将维护插入顺序,但不会允许重复。

哈希将不会维护任何插入顺序。 它是List和Set的简单组合:)