1. 程式人生 > >Java 集合之 Set 詳解與原始碼分析

Java 集合之 Set 詳解與原始碼分析

    Set集合與List一樣,都是繼承自Collection介面,常用的實現類有HashSet和TreeSet。值得注意的是,HashSet是通過HashMap來實現的而TreeSet是通過TreeMap來實現的,所以HashSet和TreeSet都沒有自己的資料結構,具體可以歸納如下:    Set集合中的元素不能重複,即元素唯一
    HashSet按元素的雜湊值儲存,所以是無序的,並且最多允許一個null物件
    TreeSet按元素的大小儲存,所以是有序的,並且不允許null物件
    Set集合沒有get方法,所以只能通過迭代器(Iterator)來遍歷元素,不能隨機訪問1.HashSet下面給出HashSet的部分原始碼,以理解它的實現方式。
static final long serialVersionUID = -5024744406713321676L;
private transient HashMap<E,Object> map;
// Dummy value to associate with an Object in the backing Map
private static final Object PRESENT = new Object();
    觀察原始碼,我們知道HashSet的資料是儲存在HashMap的例項物件map中的,並且對應於map中的key,而Object型別的引用PRESENT則是對應於map中的value的一個虛擬值,沒有實際意義。聯想到HashMap的一些特性:無序儲存、key值唯一等等,我們就可以很自然地理解Set集合元素不能重複以及HashSet無序儲存的特性了。    下面從原始碼的角度來理解HashSet的基本用法:(1) 構造器(四種)    HashSet() 空的構造器,初始化一個空的HashMap    HashSet(Collection<? extends E> c) 傳入一個子集c,用於初始化HashMap
    HashSet(int initialCapacity, float loadFactor) 初始化一個空的HashMap,並指定初始容量和載入因子    HashSet(int initialCapacity) 初始化一個空的HashMap,並指定初始容量
public HashSet() {
  map = new HashMap<>();
}
public HashSet(Collection<? extends E> c) {
  map = new HashMap<>(Math.max((int) (c.size()/.75f) + 1, 16));
  addAll(c);
}
public HashSet(int initialCapacity, float loadFactor) {
  map = new HashMap<>(initialCapacity, loadFactor);
}
public HashSet(int initialCapacity) {
  map = new HashMap<>(initialCapacity);
}
 (2) 插入元素:add(E e) 插入指定元素(呼叫HashMap的put方法實現)
Set<String> hashSet = new HashSet<String>();
hashSet.add("D");
hashSet.add("B");
hashSet.add("C");
hashSet.add("A”);
 (3) 查詢元素:contains(Object o) 判斷集合中是否包含指定的元素(呼叫HashMap的containsKey方法實現)
public boolean contains(Object o) {
return map.containsKey(o);
}
    由於HashSet的實現類中沒有get方法,所以只能通過迭代器依次遍歷,而不能隨機訪問(呼叫HashMap中keySet的迭代器實現)
public Iterator<E> iterator() {
return map.keySet().iterator();
}
     應用示例:
Set<String> hashSet = new HashSet<String>();
  hashSet.add("D");
  hashSet.add("B");
  hashSet.add("C");
  hashSet.add("A");
  for (Iterator iterator = hashSet.iterator(); iterator.hasNext();) {
   String string = (String) iterator.next();
   System.out.print(string+" ");
  }//D A B C
(4) 修改元素:由於HashMap中的key值不能修改,所以HashSet不能進行修改元素的操作(5) 刪除元素
    remove(Object o) 刪除指定元素(呼叫HashMap中的remove方法實現,返回值為true或者false)
public boolean remove(Object o) {
return map.remove(o)==PRESENT;
}
     clear() 清空元素(呼叫HashMap中的clear方法實現,沒有返回值)
public void clear() {
   map.clear();
}
2.TreeSet    TreeSet是SortedSet介面的唯一實現類。前面說過,TreeSet沒有自己的資料結構而是通過TreeMap實現的,所以TreeSet也是基於紅黑二叉樹的一種儲存結構,所以TreeSet不允許null物件,並且是有序儲存的(預設升序)。
private transient NavigableMap<E,Object> m;
// Dummy value to associate with an Object in the backing Map
private static final Object PRESENT = new Object();
    上述原始碼中的NavigableMap是繼承自SrotedMap的一個介面,其實現類為TreeMap,因此TreeSet中的資料是通過TreeMap來儲存的,此處的PRESENT也是沒有實際意義的虛擬值。
    下面從原始碼的角度來理解HashSet的基本用法:
(1) 構造器(四種)
    TreeSet() 空的構造器,初始化一個空的TreeMap,預設升序排列
    TreeSet(Comparator<? super E> comparator) 傳入一個自定義的比較器,常常用於實現降序排列
    TreeSet(Collection<? extends E> c) 傳入一個子集c,用於初始化TreeMap物件,預設升序
    TreeSet(SortedSet<E> s) 傳入一個有序的子集s,用於初始化TreeMap物件,採用子集的比較器
public TreeSet() {
  this(new TreeMap<E,Object>());
}
public TreeSet(Comparator<? super E> comparator) {
  this(new TreeMap<>(comparator));
}
public TreeSet(Collection<? extends E> c) {
  this();
  addAll(c);
}
public TreeSet(SortedSet<E> s) {
  this(s.comparator());
  addAll(s);
}
     應用示例
//自定義一個比較器,實現降序排列
  Set<Integer> treeSet = new TreeSet<Integer>(new Comparator<Integer>() {
   @Override
   public int compare(Integer o1, Integer o2) {
//    return 0;  //預設升序
    return o2.compareTo(o1);//降序
   }
  });
  treeSet.add(200);
  treeSet.add(120);
  treeSet.add(150);
  treeSet.add(110);
  for (Iterator iterator = treeSet.iterator(); iterator.hasNext();) {
   Integer integer = (Integer) iterator.next();
   System.out.print(integer+" ");
  } //200 150 120 110

ArrayList<Integer> list = new ArrayList<Integer>();
  list.add(300);
  list.add(120);
  list.add(100);
  list.add(150);
  System.out.println(list); //[300, 120, 100, 150]
   
  //傳入一個子集,預設升序排列
  TreeSet<Integer> treeSet = new TreeSet<Integer>(list);
  for (Iterator iterator = treeSet.iterator(); iterator.hasNext();) {
   Integer integer = (Integer) iterator.next();
   System.out.print(integer+" ");
  }//100 120 150 300

/*
   * 傳入一個有序的子集,採用子集的比較器
   *  注意子集的型別必須是SortedSet及其子類或者實現類,否則將採用預設的比較器
   *  所以此處subSet的型別也可以是TreeSet。
   */
   
  SortedSet<Integer> subSet = new TreeSet<Integer>(new Comparator<Integer>() {
   @Override
   public int compare(Integer o1, Integer o2) {
//    return 0;  //預設升序
    return o2.compareTo(o1);//降序
   }
  });
  subSet.add(200);
  subSet.add(120);
  subSet.add(150);
  subSet.add(110);
  for (Iterator iterator = subSet.iterator(); iterator.hasNext();) {
   Integer integer = (Integer) iterator.next();
   System.out.print(integer+" ");
  } //200 150 120 110
   
  System.out.println();
  Set<Integer> treeSet = new TreeSet<Integer>(subSet);
  for (Iterator iterator = treeSet.iterator(); iterator.hasNext();) {
   Integer integer = (Integer) iterator.next();
   System.out.print(integer+" ");
  }//200 150 120 110
   
  System.out.println();
  treeSet.add(500);
  treeSet.add(100);
  treeSet.add(105);
  for (Iterator iterator = treeSet.iterator(); iterator.hasNext();) {
   Integer integer = (Integer) iterator.next();
   System.out.print(integer+" ");
  }//500 200 150 120 110 105 100
 (2) 插入元素    add(E e) 插入指定的元素(呼叫TreeMap的put方法實現)
    addAll(Collection<? extends E> c) 插入一個子集c
ArrayList<Integer> list = new ArrayList<Integer>();
  list.add(300);
  list.add(120);
  list.add(100);
  list.add(150);
  System.out.println(list); //[300, 120, 100, 150]
  Set<Integer> treeSet = new TreeSet<Integer>();
  //插入一個子集,預設升序
  treeSet.addAll(list);
  for (Iterator iterator = treeSet.iterator(); iterator.hasNext();) {
   Integer integer = (Integer) iterator.next();
   System.out.print(integer+" ");
  }//100 120 150 300
(3) 查詢元素    contains(Object o) 判斷集合中是否包含指定物件(呼叫TreeMap的containsKey方法實現)
    與HashSet一樣,TreeSet的實現類中沒有get方法,所以只能通過迭代器依次遍歷,而不能隨機訪問(呼叫TreeMap中keySet的迭代器實現)。(4) 修改元素    TreeSet不能進行修改元素的操作,原因與HashSet一樣。
(5) 刪除元素
    remove(Object o) 刪除指定元素(呼叫TreeMap中的remove方法實現,返回true或者false)
public boolean remove(Object o) {
return m.remove(o)==PRESENT;
}
     clear() 清空元素(呼叫TreeMap中的clear方法實現,無返回值)
public void clear() {
m.clear();
}
    應用示例:
ArrayList<Integer> list = new ArrayList<Integer>();
  list.add(300);
  list.add(120);
  list.add(100);
  list.add(150);
  System.out.println(list); //[300, 120, 100, 150]
   
  Set<Integer> treeSet = new TreeSet<Integer>();
   
  //插入一個子集,預設升序
  treeSet.addAll(list);
  for (Iterator iterator = treeSet.iterator(); iterator.hasNext();) {
   Integer integer = (Integer) iterator.next();
   System.out.print(integer+" ");
  }//100 120 150 300
   
  System.out.println(treeSet.remove(100));//true
  for (Iterator iterator = treeSet.iterator(); iterator.hasNext();) {
   Integer integer = (Integer) iterator.next();
   System.out.print(integer+" ");
  }//120 150 300
   
  treeSet.clear();
  System.out.println(treeSet.size());//0