HashSet和TreeSet

对于 HashSet 而言,它是基于 HashMap 实现的,HashSet 底层采用 HashMap 来保存所有元素,因此 HashSet 的实现比较简单,查看 HashSet 的源代码,可以看到如下代码:

(1)使用HashMap的key保存HashSet的元素。

 public class HashSet<E> 
	 extends AbstractSet<E> 
	 implements Set<E>, Cloneable, java.io.Serializable 
 { 
	 // 使用 HashMap 的 key 保存 HashSet 中所有元素**************************
	 private transient HashMap<E,Object> map; 
	 // 定义一个虚拟的 Object 对象作为 HashMap 的 value ********************
	 private static final Object PRESENT = new Object(); 
	 ... 
	 // 初始化 HashSet,底层会初始化一个 HashMap 
	 public HashSet() 
	 { 
		 map = new HashMap<E,Object>(); 
	 } 
	 // 以指定的 initialCapacity、loadFactor 创建 HashSet 
	 // 其实就是以相应的参数创建 HashMap 
	 public HashSet(int initialCapacity, float loadFactor) 
	 { 
		 map = new HashMap<E,Object>(initialCapacity, loadFactor); 
	 } 
	 public HashSet(int initialCapacity) 
	 { 
		 map = new HashMap<E,Object>(initialCapacity); 
	 } 
	 HashSet(int initialCapacity, float loadFactor, boolean dummy) 
	 { 
		 map = new LinkedHashMap<E,Object>(initialCapacity 
			 , loadFactor); 
	 } 
	 // 调用 map 的 keySet 来返回所有的 key **************
	 public Iterator<E> iterator() 
	 { 
		 return map.keySet().iterator(); 
	 } 
	 // 调用 HashMap 的 size() 方法返回 Entry 的数量,就得到该 Set 里元素的个数
	 public int size() 
	 { 
		 return map.size(); 
	 } 
	 // 调用 HashMap 的 isEmpty() 判断该 HashSet 是否为空,
	 // 当 HashMap 为空时,对应的 HashSet 也为空
	 public boolean isEmpty() 
	 { 
		 return map.isEmpty(); 
	 } 
	 // 调用 HashMap 的 containsKey 判断是否包含指定 key 
	 //HashSet 的所有元素就是通过 HashMap 的 key 来保存的
	 public boolean contains(Object o) 
	 { 
		 return map.containsKey(o); 
	 } 
	 // 将指定元素放入 HashSet 中,也就是将该元素作为 key 放入 HashMap 
	 public boolean add(E e) 
	 { 
		 return map.put(e, PRESENT) == null; 
	 } 
	 // 调用 HashMap 的 remove 方法删除指定 Entry,也就删除了 HashSet 中对应的元素
	 public boolean remove(Object o) 
	 { 
		 return map.remove(o)==PRESENT; 
	 } 
	 // 调用 Map 的 clear 方法清空所有 Entry,也就清空了 HashSet 中所有元素
	 public void clear() 
	 { 
		 map.clear(); 
	 } 
	 ... 
 } 

 由上面源程序可以看出,HashSet 的实现其实非常简单,它只是封装了一个 HashMap 对象来存储所有的集合元素,所有放入 HashSet 中的集合元素实际上由 HashMap 的 key 来保存,而 HashMap 的 value 则存储了一个 PRESENT,它是一个静态的 Object 对象。 
HashSet 的绝大部分方法都是通过调用 HashMap 的方法来实现的,因此 HashSet 和 HashMap 两个集合在实现本质上是相同的。

2.因为HashSet底层是HashMap这也就说明了以下HashSet的几个特性:

 (1)HashSet是无序的

(2)HashSet是不同步的

(3)元素集合可以为null,但只能一个为空,以及set是不重复的集合。

(4)hashcode是比对key值,value不用比较。

是否相等:hashcode相等---同一个bucket,且equals(key)相等。


3.LinkedHashSet

HashSet的子类,也是通过hashcode定位bucket,然后通过equals判断是否相等,只是多了一个链表来记录添加元素的顺序。所以输出元素的顺序总是与添加顺序一致。


4.TreeSet(所有元素必须实现Comparable接口,底层红黑树)

是SortedSet接口的实现类,按照升序排序。也可以采用定制排序 Comparator 的comparator()。

自然排序,默认的就是Comparator里面的compareTo()方法进行比较。

TreeSet是基于TreeMap实现的。TreeSet中的元素支持2种排序方式:自然排序 或者 根据创建TreeSet 时提供的 Comparator 进行排序。这取决于使用的构造方法。
TreeSet为基本操作(add、remove 和 contains)提供受保证的 log(n) 时间开销

是否相等:compareTo(o1,o2)返回值是否为0,不考虑equals。所以即使equals为true,但compareTo返回值不是0,那么两个对象也不相等。

 public class TreeSet<E> extends AbstractSet<E>
       implements NavigableSet<E>, Cloneable, java.io.Serializable
   {
       // NavigableMap对象*********基于TreeMap实现的
       private transient NavigableMap<E,Object> m;
   
       // TreeSet是通过TreeMap实现的,
      // PRESENT是键-值对中的值。
      private static final Object PRESENT = new Object();
  
      // 不带参数的构造函数。创建一个空的TreeMap
      public TreeSet() {
          this(new TreeMap<E,Object>());
      }
  
      // 将TreeMap赋值给 "NavigableMap对象m"
      TreeSet(NavigableMap<E,Object> m) {
          this.m = m;
      }
  
      // 带比较器的构造函数。
      public TreeSet(Comparator<? super E> comparator) {
          this(new TreeMap<E,Object>(comparator));
      }


发布了369 篇原创文章 · 获赞 104 · 访问量 25万+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章