LinkedHashSet

来源:互联网 发布:中国历年gdp数据excel 编辑:程序博客网 时间:2024/06/09 17:06

LinkedHashSet

JAVA集合 2010-08-05 16:29:27 阅读32 评论0   字号: 订阅

LinkedHashSet
 具有可预知迭代顺序的 Set 接口的哈希表和链接列表实现。
 此实现与 HashSet 的不同之外在于,后者维护着一个运行于所有条目的双重链接列表。
 此链接列表定义了迭代顺序,即按照将元素插入到集合中的顺序(插入顺序)进行迭代。
 注意,插入顺序不受在集合中重新插入的元素的影响。、
 (如果在 s.contains(e) 返回 true 后立即调用 s.add(e),则元素 e 会被重新插入到集合 s 中。)
 此实现可以让客户免遭未指定的、由 HashSet 提供的通常杂乱无章的排序工作,
 而又不致引起与 TreeSet 关联的成本增加。使用它可以生成一个与原来顺序相同的集合副本,
 并且与原集合的实现无关:
     void foo(Set m) {
         Set copy = new LinkedHashSet(m);
         ...
     }
 如果模块通过输入得到一个集合,复制这个集合,然后返回由此副本决定了顺序的结果,
 这种情况下这项技术特别有用。(客户通常期望内容返回的顺序与它们出现的顺序相同。)
 此类提供所有可选的 Set 操作,并且允许 null 元素。与 HashSet 一样,它可以为基本操作(add、contains 和 remove)提供稳定的性能,
 假定哈希函数将元素正确地分布到存储段中。由于增加了维护链接列表的开支,其性能很可能会比 HashSet 稍逊一筹,
 不过,这一点例外:LinkedHashSet迭代所需时间与集合的大小成正比,而与容量无关。
 HashSet 迭代很可能支出较大,因为它所需迭代时间与其容量成正比。
 链接的哈希集合有两个影响其性能的参数:初始容量和加载因子。它们与 HashSet 中的定义极其相同。
 注意,为初始容量选择非常高的值对此类的影响比对HashSet要小,因为此类的迭代时间不受容量的影响。
 注意,此实现不是同步的。如果多个线程同时访问链接的哈希集合,而其中至少一个线程修改了该集合,
 则它必须 保持外部同步。这一般通过对自然封装该集合的对象进行同步操作来完成。
 如果不存在这样的对象,则应该使用 Collections.synchronizedSet 方法来“包装”该集合。
 最好在创建时完成这一操作,以防止意外的非同步访问:
     Set s = Collections.synchronizedSet(new LinkedHashSet(...));
 此类的 iterator 方法返回的迭代器是快速失败 的:在迭代器创建之后,如果对集合进行修改,
 除非通过迭代器自身的移除方法,其他任何时间任何方式的修改,迭代器都将抛出 ConcurrentModificationException。
 因此,面对并发的修改,迭代器很快就会完全失败,而不冒将来不确定的时间任意发生不确定行为的风险。
 注意,迭代器的快速失败行为不能得到保证,一般来说,存在不同步的并发修改时,不可能作出任何强有力的保证。
 快速失败迭代器尽最大努力抛出 ConcurrentModificationException。
 因此,编写依赖于此异常的程序的方式是错误的,正确做法是:迭代器的快速失败行为应该仅用于检测程序错误。
 注意1:允许 null 元素,但最多只能加一个。如果LinkedHashSet已经有null元素,
 试图再加null,不会成功,也不会抛异常。
 注意2:实现不同步的,不是线程安全的。
 注意3:此类的iterator方法返回的迭代器是快速失败 的:在创建迭代器之后,如果对集合进行修改,
 除非通过迭代器自身的 remove 方法,否则在任何时间以任何方式对其进行修改,
 Iterator 都将抛出 ConcurrentModificationException
 注意4:iterator()返回的迭代器,里面的元素是插入的顺序排序的(先插入的在前面).
 注意5:关于对象的相等和HashSet一样。
 具体可以查考HashSet和《hashcode()和equals()及HashSet判断对象相等》
 注意6:文档中说”为初始容量选择非常高的值对此类的影响比对HashSet要小“,应是指迭代时间的影响。
 注意7:文档中以下描述
 ”(如果在 s.contains(e) 返回 true 后立即调用 s.add(e),则元素 e 会被重新插入到集合 s 中。)“
 不正确事实是:当试图添加一个重复元素到LinkedHashSet时,新元素并不会把旧元素替换掉,
 而只是新元素不会添加到LinkedHashSet不会抛异常

 当然如果插入重复元素,是以第一次插入的顺序为准。例1就是个很好的证明。
 例1:
import java.util.LinkedHashSet;
public class Test {
 /**
  * @param args
  */
 public static void main(String[] args) {
  LinkedHashSet<People> set=new LinkedHashSet();
  set.add(new People("robin",1,21));
  set.add(new People("hb",2,20));
  set.add(new People("harry",9,30));
  set.add(null);
  People p4=new People("robin",4,25);
  set.add(p4);
  set.add(new People("yp",5,28));
  set.add(new People("yp2",8,28));
  set.add(null);
  set.add(null);
  for(People p:set)
   System.out.println(p);
 }
}
class People{
 String name;
 int id;
 int age;
 public People(String name,int id)
 {
  this(name,id,0);
 }
 public People(String name,int id,int age)
 {
  this.name=name;
  this.id=id;
  this.age=age;
 }
 public String toString()
 {
  return id+name+age;
 }
 public boolean equals(Object o)
 {
  if(o==null)
   return false;
  if(!(o instanceof People))
   return false;
  People p=(People)o;
  boolean res=name.equals(p.name);
  if(res)
   System.out.println("name "+name+" is double");
  else
   System.out.println(name+" vS "+p.name);
  return res;
 }
 public int hashCode()
 {
  return name.hashCode();
 }
}
原创粉丝点击