HashSet与LinkedHashSet


153

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

LinkedHashSet是HashSet的有序版本,可在所有元素上维护双链列表。当您关心迭代顺序时,请使用此类而不是HashSet。当您遍历HashSet时,顺序是不可预测的,而LinkedHashSet可让您按插入元素的顺序来遍历元素。

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


2
使用Intellij(Ctrl + B)选项跟踪答案。:)
Delta

当然,您需要附加源代码。:)
Delta

Answers:


65

答案就在其中构造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);
}

2
父类具有显
式子

5
使用伪参数构造函数消除歧义的设计并非完全干净。
埃里克·J.

8
这是相当干净的设计,因为API是干净的(此HashSet构造函数是程序包私有的)。实现细节对于该类的用户而言并不重要。维护此代码可能会比较困难,但是对于java.util类,即使很小的性能改进也可以证明这一点。
lbalazscs 2015年

25

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

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

如您所见,内部地图是LinkedHashMap。如果您向里看LinkedHashMap,您会发现以下字段:

private transient Entry<K, V> header;

这是有问题的链表。


24

HashSet的无序的未分类的设置。
LinkedHashSet是HashSet 的有序版本

HashSetLinkedHashSet之间的唯一区别是:
LinkedHashSet保持插入顺序。

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

LinkedHashSet保持插入顺序的原因是:
底层使用的数据结构是Doubly-Linked-List


9

您应该查看HashSet它调用的构造函数的源代码……这是一个特殊的构造函数,它使Mapa 成为后盾,LinkedHashMap而不仅仅是a HashMap


谢谢,在HashSet中有用于创建LinkedHashMap的构造函数,该构造函数在LinkedHashSet中调用,所有逻辑在LinkedHashMap中
Shikarn-O 2011年

5

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

  1. 可预测的 迭代顺序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

您可以在此处查看源测试页:最终性能测试示例


2
在这些“基准”之前,我看不到JVM的任何预热,因此我不会认真对待任何这些数据。阅读更多
Felix S

3

HashSet:实际上是无序的。如果您传递参数意味着

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

输出:可能2,1,3无法预测。下次再下单。

LinkedHashSet() 产生FIFO命令。


3

HashSet 不保持插入项目的顺序
LinkedHashSet 保持插入项目的顺序

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

2

哈希集:

带下划线的数据结构是哈希表。不允许重复对象。插入顺序不会保留,它基于对象的哈希码。空插入是可能的(仅一次)。它实现了可序列化,可克隆但不实现RandomAccess接口。如果频繁操作是搜索操作,则最好选择HashSet。

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

构造函数:

HashSet h = new HashSet(); 创建一个空的HashSet对象,其默认初始容量为16且默认填充比率(负载系数)为0.75。

HashSet h = new HashSet(int initialCapacity); 创建一个具有指定initialCapacity的空HashSet对象,默认填充率为0.75。

HashSet h = new HashSet(int initialCapacity,float fillRatio);

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

LinkedHashSet:

它是HashSet的子类。除了以下区别之外,它与HashSet包括(构造函数和方法)完全相同。

差异HashSet:

  1. 带下划线的数据结构是哈希表。
  2. 不保留插入顺序。
  3. 推出了1.2版本。

LinkedHashSet:

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

1

如果看一下从LinkedHashSet类调用的构造函数,您会发现在内部它LinkedHashMap是用于支持目的的。


0

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

哈希集将不保留任何插入顺序。它是List和Set简单的组合:)

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.