Set 接口的哈希表和链表实现,具有可预测的迭代顺序。 此实现与 HashSet 的不同之处在于,它维护一个贯穿其所有条目的双向链表。此链表定义迭代顺序,即元素插入集合的顺序(插入顺序)。请注意,如果将元素重新插入到集合中,则插入顺序不受影响。(如果调用了 s.add(e),而 s.contains(e) 在调用之前将返回 true,则元素 e 将重新插入到集合 s 中。
此实现使其客户端免于 提供的未指定的、通常混乱的排序 HashSet,而不会产生与 TreeSet相关的增加成本。它可用于生成与原始集合具有相同顺序的集合的副本,而不管原始集合的实现如何:

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

如果模块在输入上获取一个集合,复制它,然后返回由副本顺序决定的结果,则此技术特别有用。 (客户通常喜欢以与呈现相同的顺序返回内容。
此类提供所有可选的 Set 操作,并允许 null 元素。与 HashSet 一样,它为基本操作(添加、包含和删除)提供恒定时间性能,前提是哈希函数在存储桶中正确分散元素。性能可能略低于 HashSet,因为维护链表会增加费用,但有一个例外:对 LinkedHashSet 进行迭代需要与集合大小成正比的时间,而不管其容量如何。对 HashSet 的迭代可能更昂贵,需要与其容量成正比的时间。
链接哈希集有两个影响其性能的参数: 初始容量 和 负载因子。 它们的定义与 HashSet 完全相同。但请注意,此类为初始容量选择过高值的惩罚不如 HashSet 严重,因为此类的迭代时间不受容量的影响。
请注意,此实现不是同步的。 如果多个线程同时访问链接的哈希集,并且至少有一个线程修改了该集, 则必须在外部 同步该哈希集。这通常是通过在自然封装集合的某个对象上进行同步来实现的。如果不存在此类对象,则应使用该 Collections.synchronizedSet 方法“包装”该集。最好在创建时执行此操作,以防止意外地对集合进行不同步访问:
Set s = Collections.synchronizedSet(new LinkedHashSet(...));
此类的迭代器方法返回的迭代器是快速失败的:如果在创建迭代器后的任何时间修改集合,则迭代器将抛出一个 . ConcurrentModificationException因此,在面对并发修改时,迭代器会快速而干净地失败,而不是冒着在未来不确定的时间出现任意的、非确定性行为的风险。
请注意,无法保证迭代器的快速失效行为,因为一般来说,在存在不同步的并发修改的情况下,不可能做出任何硬性保证。快速失败迭代器会尽力而为地抛出 ConcurrentModificationException 。因此,编写一个依赖于此异常的程序的正确性是错误的: 迭代器的快速失败行为应该只用于检测错误。

特性

  • 底层数据结构采用链表哈希表共同实现,链表保证了元素的顺序与存储顺序一致,哈希表保证了元素的唯一性。
  • 线程不安全,效率高。