java集合之Set

转载自   http://yeniu33zmz.blog.163.com/blog/static/28961848200982844927347/


java集合大致上可分为:set,list,map三种体系,其中set代表无序不可重复的集合,list代表有序可重复的集合,map代表具有映射关系的集合。后来又增加一种Queue体系集合,代表一种队列的集合实现。

set和list接口都实现了collection接口

使用Iterator接口遍历集合元素
import java.util.Collection;
import java.util.HashSet;
import java.util.Iterator;

public class TestIterator {

 /**
  * @param args
  */
 public static void main(String[] args) {
  // TODO Auto-generated method stub
  //创建一个集合
  Collection books = new HashSet();
  books.add("book1");
  books.add("book2");
  books.add("book3");
  books.add("book4");
  //获取Iterator迭代器
  Iterator it = books.iterator();
  while(it.hasNext()){
   //it.next()方法返回的数据类型是Object类型,需要强制类型转换
   String book = (String)it.next();
   System.out.println(book);
   if(book.equals("book3")){
    //从集合中***上一次next返回的元素
    it.remove();
    //使用Iterator迭代器过程中,不可修改集合元素,所以下面代码引发异常
    //books.remove("book3");
   }
   //对book变量赋值,不会改变元素本身
   book= "book9";
  }
  System.out.println(books);
 }

}

Iterator必须依附于Collection对象。有一个Iterator对象,则必然有一个与之关联的的Collection对象。

使用foreach遍历集合元素更加简洁
import java.util.Collection;
import java.util.HashSet;

public class TestIterator {

 /**
  * @param args
  */
 public static void main(String[] args) {
  // TODO Auto-generated method stub
  //创建一个集合
  Collection books = new HashSet();
  books.add("book1");
  books.add("book2");
  books.add("book3");
  books.add("book4");
  for(Object obj : books)
  {
   String book = (String)obj;
   System.out.println(book);
   if(book.equals("book3")){
   
    //使用循环过程中,不可修改集合元素,所以下面代码引发异常
    //books.remove("book3");
   }
  }

  System.out.println(books);
 }

}

Set接口

实际上Set就是Collection,只是Set不允许包含重复元素

Set通过equals方法判断两个对象是否相同,而不是==,所以只要equals返回true,

那么两个对象就是相同的,无论实际上这两个对象差别有多大,而只要equals返回false,即使两个对象实际上是同一个对象,Set也会当成两个对象处理。
例如:
import java.util.HashSet;
import java.util.Set;

public class TestSet {

 /**
  * @param args
  */
 public static void main(String[] args) {
  // TODO Auto-generated method stub
  Set books = new HashSet();
  books.add("book1");
  boolean result = books.add(new String("book1"));
  System.out.println(result);
  System.out.println(books);
 }

}
将输出false book1

HashSet,TreeSet,EnumSet三个类实现了Set接口

 

HashSet类
HashSet具有的特点:
1 不能保证元素的排列顺序,顺序可能发生变化。
2 HashSet不是同步的,如果多个线程同时访问一个Set集合,如果多个线程同时访问一个HashSet,如果有2条或者以上的线程修改了  HashSet集合时,必须通过代码来保证其是同步的(TreeSet和EnumSet也一样)。
3 集合元素可以是null。

HashSet判断两个元素相等是的标准是两个对象通过equals方法比较相等,并且两个对象的hashCode方法返回的值也相等。
如果equals比较相等,hashCode返回值不同,则HashSet将会把两个对象保存到不同的位置,即都添加成功
如果equals不相等,hashCode返回值相等,则HashSet将会试图把两个对象保存到同一个位置,实际上又不行,处理起来将很复杂,将导致性能下降。

所以,重写某个类的equals方法和hashCode方法时,应该尽量保证对象通过equals返回true是,它们的hashCode返回值也相等。

重写hashCode的基本规则
1 过equals返回true是,它们的hashCode返回值也相等
2 对象中用作equals比较标准的属性,都应该用来计算hashCode值。

当向HashSet中添加可变对象是,必须非常的小心,如果修改HashSet中的对象时,有可能导致该对象与集合中的其他对象相等,从而导致HashSet无法准确访问该对象。

HashSet的子对象LinkedHashSet使用链表维护元素次序,使元素以插入顺序保存,性能略低于HashSet。

 

TreeSet类
TreeSet是SortedSet接口的唯一实现,可以确保元素处于排序状态
TreeSet通用方法示例:
import java.util.TreeSet;

public class TestTreeSet {

 /**
  * @param args
  */
 public static void main(String[] args) {
  // TODO Auto-generated method stub
  TreeSet nums = new TreeSet();
  //向TreeSet添加4个Integer对象
  nums.add(5);
  nums.add(2);
  nums.add(10);
  nums.add(-9);
  //输出集合元素
  System.out.println(nums);
  //输出集合里的第一个元素
  System.out.println(nums.first());
  //输出集合里的最后一个元素
  System.out.println(nums.last());
  //返回小于4的子集、不包含4
  System.out.println(nums.headSet(4));
  //返回大于5的子集、包含5
  System.out.println(nums.tailSet(5));
  //返回大于-3,小于4的子集
  System.out.println(nums.subSet(-3, 4));
 }

}


与HashSet集合采用hash算法来决定元素的存储位置不同,TreeSet集合采用红黑树的数据结构来对元素进行排序,分自然排序和定制排序俩种,默认的情况下采用自然排序。

试图把一个对象添加到TreeSet时,该对象的类必须实现Comparable接口,否则出现异常(添加第一个时没事,添加第二个时,TreeSet调用该对象的CompareTo(Object obj)方法时引发异常),而且向TreeSet添加的对象应该属于同一个类的对象,否则也会引发异常。

一些常用类已经实现了Comparable接口,比如BigDecimal,BigInteger,Character,Boolean(true>false),String,Date,Time等
对于TreeSet而言,判断两个对象不相等的标准是:equals方法返回false,或compareTO方法没有返回0,即使两个对象是同一个对象也会当做两个对象处理。所有当重写一个须放入TreeSet的类的equals方法时,应该保证与compareTo方法有一致的结果。

如果向TreeSet中添加一个可变对象后,并且后面的程序修改了该对象的属性,导致它与其他对象的大小发生了变化,但TreeSet不会再次调整它们的顺序,甚至导致保存的这两个对象通过equals返回true,而compareTo确返回0,所有推荐HashSet和TreeSet集合中只放入不可变对象。

示例:
import java.util.TreeSet;

class R implements Comparable{
 int count;
 public R(int count){
  this.count = count;
 }
 public String toString(){
  return "R(count属性:"+count+")";
 }
 public boolean equals(Object obj){
  if(obj instanceof R){
   R r = (R)obj;
   if(r.count == this.count){
    return true;
   }
  }
  return true;
 }
 public int compareTo(Object obj){
  R r = (R)obj;
  if(this.count > r.count)
  {
   return 1;
  }
  else if(this.count == r.count){
   return 0;
  }
  else {
   return -1;
  }
 }
}

public class TestTreeSet2 {

 /**
  * @param args
  */
 public static void main(String[] args) {
  // TODO Auto-generated method stub
  TreeSet ts = new TreeSet();
  ts.add(new R(5));
  ts.add(new R(-3));
  ts.add(new R(9));
  ts.add(new R(-2));
  System.out.println(ts);
     // 取出第一个元素
  R frist = (R)ts.first();
  //改变其属性值
  frist.count = 20;
  //取出最后一个元素
  R last = (R)ts.last();
  //改变其属性值
  last.count = -2;
  System.out.println(ts);
  //***已更改的元素失败
  ts.remove(new R(-2));
  System.out.println(ts);
  //***未更改的元素成功
  ts.remove(new R(5));
  System.out.println(ts);
 }

}

EnumSet
EnumSet是一个专门为枚举类设计的集合,内部以向量的方式存储,占用内存很少,运行效率很高
EnumSet不允许加入null元素,否则会出现异常
当试图复制一个Collection集合里的元素来创建EnumSet集合时,必须保证Collection集合里的所有元素都是同一个枚举类的枚举值。
示例:
import java.util.EnumSet;

enum Season{
 SPRING,SUMMER,FALL,WINTER;
}

public class EnumSetDemo {

 /**
  * @param args
  */
 public static void main(String[] args) {
  // TODO Auto-generated method stub
  EnumSet es1 = EnumSet.allOf(Season.class);
  System.out.println(es1);
  EnumSet es2 = EnumSet.noneOf(Season.class);
  System.out.println(es2);
  es2.add(Season.WINTER);
  es2.add(Season.SPRING);
  System.out.println(es2);
  //输出summer,winter
  EnumSet es3 = EnumSet.of(Season.SUMMER,Season.WINTER);
  System.out.println(es3);
  //输出summer,fall,winter
  EnumSet es4 = EnumSet.range(Season.SUMMER, Season.WINTER);
  System.out.println(es4);
  //获得es4的余集
  EnumSet es5 = EnumSet.complementOf(es4);
  //输出spring
  System.out.println(es5);
 }

}

 


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章