前言
- Set接口的哈希表和链表实现,具有可预测的迭代顺序。
- 此实现与HashSet的不同之处在于,它维护在其所有条目中运行的双向链接列表。
- 此链表定义了迭代顺序,即元素插入到集合中的顺序(插入顺序)。
- 请注意,如果将元素重新插入到集合中,则插入顺序不会受到影响。
- 此类提供所有可选的Set操作,并允许空元素。
- 像HashSet一样,它为基本操作(添加,包含和删除)提供恒定时间的性能,假设哈希函数将元素正确地分散在存储桶中。
- 由于维护链接列表会增加开销,因此性能可能会略低于HashSet,
- 但有一个例外:在LinkedHashSet上进行迭代需要的时间与集合的大小成正比,而不论其容量如何。
- 在HashSet上进行迭代可能会更昂贵,需要的时间与其容量成正比。
- 链接的哈希集具有两个影响其性能的参数:初始容量和负载因子。
- 它们的定义与HashSet一样。
- 但是请注意,与HashSet相比,此类为初始容量选择过高的值的惩罚不那么严重,因为此类的迭代时间不受容量的影响。
- 请注意,此实现未同步。
- 如果多个线程同时访问链接的哈希集,并且至少有一个线程修改了该哈希集,则必须在外部对其进行同步。
- 通常,通过在自然封装了该集合的某个对象上进行同步来实现。
- 如果不存在这样的对象,则应使用 Collections.synchronizedSet 方法来“包装”该集合。
- 最好在创建时完成此操作,以防止意外地异步访问集合:
- Set s = Collections.synchronizedSet(new LinkedHashSet(...));
- 此类的迭代器方法返回的迭代器是快速失败的:
- 如果在创建迭代器之后的任何时间以任何方式修改集合(通过迭代器自己的remove方法除外),
- 则迭代器将抛出{@link ConcurrentModificationException}。
- 因此,面对并发修改,迭代器会快速干净地失败,而不会在未来的不确定时间内冒任意,不确定的行为的风险
- 注意,迭代器的快速失败行为无法得到保证,因为通常来说,在存在不同步的并发修改的情况下,不可能做出任何严格的保证。
- 快速失败的迭代器会尽最大努力抛出ConcurrentModificationException。
- 因此,编写依赖于此异常的程序的正确性是错误的:迭代器的快速失败行为仅应用于检测错误。
源码
public class LinkedHashSet<E>
extends HashSet<E>
implements Set<E>, Cloneable, java.io.Serializable {
private static final long serialVersionUID = -2851667679971038690L;
public LinkedHashSet(int initialCapacity, float loadFactor) {
super(initialCapacity, loadFactor, true);
}
public LinkedHashSet(int initialCapacity) {
super(initialCapacity, .75f, true);
}
public LinkedHashSet() {
super(16, .75f, true);
}
public LinkedHashSet(Collection<? extends E> c) {
super(Math.max(2*c.size(), 11), .75f, true);
addAll(c);
}
@Override
public Spliterator<E> spliterator() {
return Spliterators.spliterator(this, Spliterator.DISTINCT | Spliterator.ORDERED);
}
}
问题记录