HashSet 与 LinkedHashSet

他们之间有什么区别? 我知道

LinkedHashSet 是 HashSet 的有序版本 维护一个跨所有元素的双链接 List。使用此类代替 HashSet 当您关心迭代顺序时 顺序是不可预测的,而 LinkedHashSet 允许您对元素进行迭代 按照插入的顺序。

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

130687 次浏览

您应该查看它调用的 HashSet构造函数的源代码... ... 它是一个特殊的构造函数,使得支持的 Map成为 LinkedHashMap,而不仅仅是 HashMap

正如你所说,这两者的区别在于:

LinkedHashSetHashSet的有序版本,它在所有元素之间维护一个双链表。当您关心迭代顺序时,请使用此类而不是 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;

这是有问题的链表。

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

哈希集: 实际上是无序的。 如果传递参数意味着

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

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

产生先进先出订单的 LinkedHashSet()

HashSet 无序没有分类集。
LinkedHashSet 是 HashSet 的 订购版本

HashSetLinkedHashSet的唯一区别是:
LinkedHashSet 维护插入顺序。

当我们遍历 HashSet时,顺序是不可预测的,而对于 LinkedHashSet,顺序是可预测的。

LinkedHashSet保持插入顺序的原因是:
底层使用的数据结构是 双链表

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

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

我建议你大部分时间使用 LinkedHashSet,因为它有 整体表现更佳) :

  1. 可预测性 > 迭代顺序 < a href = “ https://docs.Oracle.com/javase/7/docs/api/java/util/LinkedHashSet.html”rel = “ noReferrer”> LinkedHashSet (Oracle)
  2. LinkedHashSet 的插入成本比 HashSet 高;
  3. 一般来说,性能比 HashMap稍好一些,因为大多数时候我们使用 Set 结构进行迭代。

性能测试:

------------- 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

您可以在这里看到源代码测试页面: 最终性能测试示例

哈希集:

带下划线的数据结构是 Hashtable。 不允许重复对象。不保留插入顺序,插入顺序基于对象的哈希代码。 空插入是可能的(只有一次)。 它实现了可序列化、可克隆但不是随机访问接口。 如果频繁操作是搜索操作,最好选择哈希集。

在 HashSet 中,如果用户试图在没有任何编译或运行时异常的情况下插入重复项,则不允许重复项。Add 方法返回简单的 false。

建造商:

HashSet h = new HashSet () ; 创建一个空的 HashSet 对象,默认初始容量为16,默认填充率(Load factor)为0.75。

HashSet h = new HashSet (int initialScale) ; 创建一个空的 HashSet 对象,该对象具有指定的 initialScale,缺省填充比率为0.75。

HashSet h = new HashSet (int initial咽容量,浮点填充率) ;

HashSet h = new HashSet (Collection c) ; 为给定的集合创建等效的 HashSet 对象。此构造函数用于集合对象之间的内部转换。

LinkedHashSet:

它是 HashSet 的子类。它与 HashSet 包括(构造函数和方法)完全相同,只是有以下差异。

差异 哈希集:

  1. 带下划线的数据结构是 Hashtable。
  2. 插入顺序不保留。
  3. 1.2版本。

LinkedHashSet:

  1. 带下划线的数据结构是 LinkedList 和 Hashtable 的组合。
  2. 插入顺序保留。
  3. 在1.4版本中引入。

插入项的顺序
插入项的顺序

例子

Set<String> set = ...;// using new HashSet<>() OR new LinkedHashSet<>()
set.add("2");
set.add("1");
set.add("ab");
for(String value : set){
System.out.println(value);
}

HashSet输出

1
ab
2

LinkedHashSet输出

2
1
ab