HashSet和TreeSet

本文深入探讨了HashSet的工作原理,包括其内部实现机制、基于HashMap的存储方式以及如何保证元素的唯一性。同时,还介绍了HashSet的一些关键特性,如无序性和不同步性,并对比了LinkedHashSet和TreeSet的区别。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值