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);
 }

}

 


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