Java LinkedHashSet 详解 - TongtongLan/Java GitHub Wiki

Set接口的哈希表和链表实现,具有可预测的迭代顺序。 这个实现与HashSet的不同之处在于,它维护一个双向链表,并在其所有条目中运行。 这个链表定义了迭代排序,这是元素插入到集合(插入顺序)的顺序。 请注意,如果将元素重新插入到集合中,则插入顺序不受影响。 (如果s.contains(e)在调用之前立即返回true,则调用s.add(e)时,将元素e重新插入到集合s中。

这种实现将客户端从HashSet提供的未指定的,通常是混乱的排序中排除,而不会增加与TreeSet相关的成本增加。 它可以用来生成一个与原始序列相同的集合的副本,而不管原始集合的实现如何:

Code example

 void foo(Set s) {
     Set copy = new LinkedHashSet(s);
     ...
 }

这个类提供了所有可选的Set操作,并允许空元素。像HashSet一样,它为基本操作(添加,包含和删除)提供了恒定时间的性能,假设散列函数正确地在元素之间分散元素。由于增加了维护链表的开销,性能可能略低于HashSet的性能,但有一个例外:对LinkedHashSet的迭代需要与集合的大小成比例的时间,而不管其容量如何。在HashSet上迭代可能会更加昂贵,需要的时间与其容量成正比。

链接哈希集有两个影响其性能的参数:初始容量和负载因子。它们的定义与HashSet完全相同。但是请注意,对于这个类别,初始容量选择过高值的影响不如HashSet大,因为这个类别的迭代次数不受容量的影响。

请注意,此实现不同步。如果多个线程同时访问链接的哈希集合,并且至少有一个线程修改了集合,则必须在外部进行同步。这通常是通过对一些自然封装集合的对象进行同步来完成的。如果不存在这样的对象,则应该使用Collections.synchronizedSet方法来“包装”该集合。这最好在创建时完成,以防止意外的不同步访问集合:

Set s = Collections.synchronizedSet(new LinkedHashSet(...));

这个类的迭代器方法返回的迭代器是快速失败的:如果在迭代器创建后随时修改集合,除了通过迭代器自己的remove方法以外,迭代器将抛出ConcurrentModificationException异常。因此,在并发修改的情况下,迭代器快速而干净地失败,而不是在未来的未定的时间冒着任意的,不确定的行为冒险。

请注意,迭代器的故障快速行为无法得到保证,因为一般来说,不可能在存在非同步并发修改的情况下做出任何硬性保证。失败快速迭代器尽最大努力抛出ConcurrentModificationException。因此,编写一个依赖于这个异常的程序是正确的:迭代器的快速失败行为只能用来检测错误。

有四个构造器方法

  • LinkedHashSet()

Constructs a new, empty linked hash set with the default initial capacity (16) and load factor (0.75).

  • LinkedHashSet(Collection<? extends E> c)

Constructs a new linked hash set with the same elements as the specified collection.

  • LinkedHashSet(int initialCapacity)

Constructs a new, empty linked hash set with the specified initial capacity and the default load factor (0.75).

  • LinkedHashSet(int initialCapacity, float loadFactor)

Constructs a new, empty linked hash set with the specified initial capacity and load factor.