HashSet 和 TreeSet - 适配器模式的应用

本文详细解析了Java中的HashSet和TreeSet的实现原理。HashSet通过HashMap实现,不允许重复元素,而TreeSet利用NavigableMap进行排序,实现了SortedSet接口。文章提供了源码链接,并介绍了Set接口的基本操作和相关接口SortedSet、NavigableSet的功能。
摘要由CSDN通过智能技术生成

概述

Java 集合接口听得最多的应该就是 List、Queue、Set、Map。

Set 的实现类重要的不多,而且源码也不复杂,甚至觉得没啥可讲的。

这一篇就汇总贴一下源码注释吧,也不过多介绍了: HashSet、TreeSet

还是老规矩,先把源码放上:


Set 接口

首先说下 Set 接口设计的定义:

一个不包含重复元素的容器,即不满足 e1.equals(e2) 条件。

Set 接口的官方注释中有这么一句: 如果允许 null,只允许存在一个 null

作为一个接口,这里就列一下它的方法和设计要求,具体使用在实现类里讲解。

查询操作

方法名/参数/返回值 接口设计约束
int size(); 返回此集合中的元素数。如果此集包含超过 Integer.MAX_VALUE,则返回 Integer.MAX_VALUE。
boolean isEmpty(); 如果集合不包含任何元素,则返回true
boolean contains(Object o); 如果此集合包含指定的元素,则返回 true。
更正式地讲,当且仅当此集合包含一个元素 e,使得(o == null?e == null:o 时,才返回 true)。
Iterator iterator(); 返回此集合中元素的迭代器。元素以不特定的顺序返回(除非此集合是提供保证的某些类的实例)。
Object[] toArray();
T[] toArray(T[] a);
转数组

修改操作

方法名/参数/返回值 接口设计约束
boolean add(E e); 如果指定的元素尚不存在,则将其添加到该集合(可选操作)
更正式地讲,如果集合中不包含任何元素 e2 ,满足e == null?e2 == null :e.equals(e2)
如果此集合已经包含元素,则调用将使该集合保持不变,并返回 false
结合构造函数上的限制,可以确保集合永远不会包含重复元素
boolean remove(Object o); 如果存在指定的元素,则从该集合中删除(可选操作)
更正式地讲,删除元素 e,满足o == null?e == null:o.equals(e)
如果此集合包含元素,则返回 true(或者等效地,如果此集合作为调用结果更改)
一旦调用返回,此集合将不包含该元素。

其他操作

方法名/参数/返回值 接口设计约束
boolean containsAll(Collection<?> c); 判断包含全部
boolean addAll(Collection<? extends E> c); 批量添加
boolean retainAll(Collection<?> c); 删除差集
boolean removeAll(Collection<?> c); 删除交集
void clear(); 删除所有元素,操作后集合为空
boolean equals(Object o); 两个集合具有相同的大小,指定集合的每个成员都包含在此集合中,则返回 true
此定义确保 equals方法可在set接口的不同实现中正常工作
int hashCode(); 返回此集合的哈希码值
集合的哈希码定义为集合中元素的哈希码之和,其中null元素的哈希码为零。

HashSet 源码

HashSet 通过内部维护一个 HashMap 来实现。主要就以下几点:

  • 添加到 HashSet 的元素作为 HashMap 的 Key
  • 所有 HashMap 的 Value 共用一个 static finalnew Object

HashMap源码可以看看以前写过的 : https://blog.csdn.net/m0_46144826/article/details/106300438

实在没什么好讲的,贴下代码略过了。。。。

/**
 * 此类实现 Set接口,并由哈希表(实际上是 HashMap实例)支持。
 * 它不保证集合的迭代顺序,特别是,它不能保证顺序会随着时间的推移保持恒定。此类允许null元素。<p>
 *
 * 此类为基本操作提供恒定的时间性能(添加,删除,包含和大小),假设哈希函数将元素正确分散在各个存储桶中。
 * 对此集合进行迭代需要的时间与 HashSet实例的大小(元素数)之和加上 HashMap实例的“容量”(数量之和)成比例个桶。
 * 因此,如果迭代性能很重要,则不要将初始容量设置得过高(或负载因数过低),这一点非常重要。<p>
 *
 * <strong>请注意,此实现未同步。</ strong>
 * 如果多个线程同时访问 hashset,并且线程中的至少一个修改了哈希集,则必须外部同步。
 * 这通常是通过对某些自然封装了该对象的对象进行同步来完成的。<p>
 *
 * 如果不存在这样的对象,则应使用{@link Collections#synchronizedSet Collections.synchronizedSet} 方法来“包装”该集合。
 * 最好在创建时执行此操作,以防止意外异步访问集合:
 * <pre> * Set s = Collections.synchronizedSet(new HashSet(...)); </ pre><p>
 *
 *此类的iterator方法返回的迭代器为<i>fail-fast</ i>:
 * 如果在创建迭代器后的任何时间修改了集合,则除通过迭代器自己的remove法外,迭代器将引发{@link ConcurrentModificationException}。<p>
 *
 * 请注意,不能保证迭代器的快速失败行为,因为通常来说,在存在不同步的并发修改的情况下,不可能做出任何硬性保证。
 * 快速失败的迭代器尽最大努力抛出<tt> ConcurrentModificationException </ tt>。
 * 因此,编写依赖于此异常的程序的正确性是错误的:<i>迭代器的快速失败行为仅应用于检测错误。</ i>
 *
 * @param <E> 此集合所维护的元素类型
 * @since   1.2
 */
public class HashSet<E>
    extends AbstractSet<E>
    implements Set<E>, Cloneable, java.io.Serializable
{
   
    static final long serialVersionUID = -5024744406713321676L;

    private transient HashMap<E,Object> map;

    // 在 HashMap中与key对应的虚拟值,所有 HashSet公用一个
    private static 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值