09、HashSet、TreeSet、LinkedHashSet 源码解析

Set类集合通过组合不同的Map,实现各种Set的功能,HashSet组合的是HashMap,TreeSet组合的是TreeMap,而LinkedHashSet则是继承HashSet,HashSet和TreeSet之所以采用组合而不是继承的方式,是因为:

  1. 继承表示父子类是同一个事物,而 Set 和 Map 本来就是想表达两种事物,所以继承不妥,而且 Java 语法限制,子类只能继承一个父类,使用继承后续难以扩展;
  2. 组合更加灵活,可以任意的组合现有的基础类,并且可以在基础类方法的基础上进行扩展、编排等,而且方法命名可以任意命名,无需和基础类的方法名称保持一致;

在工作中,如果碰到类似问题,我们的原则也是尽量多用组合,少用继承。

HashSet源码解析

HashSet底层基于HashMap实现,所以HashMap的大部分特性HashSet也有,例如:

  1. 无法保证元素顺序,迭代时不能保证按照插入顺序,或者其它顺序进行迭代;
  2. 线程不安全,如果需要安全要自行加锁,或者使用 Collections.synchronizedSet;
  3. 迭代过程中,如果数据结构被改变,会快速失败,抛出 ConcurrentModificationException 异常;
HashSet组合的源码实现
// 把 HashMap 组合进来,key 是 Hashset 的 key,value 是下面的 PRESENT
private transient HashMap<E,Object> map;
// HashMap 中的 value
private static final Object PRESENT = new Object();

HashSet中的元素就是HashMap中的key,HashMap中的value是个固定值。

HashSet初始化

初始化源码如下:

// 对 HashMap 的容量进行了计算
public HashSet(Collection<? extends E> c) {
    map = new HashMap<>(Math.max((int) (c.size()/.75f) + 1, 16));
    addAll(c);
}

从源码中可以学习到初始化HashMap时如何指定容量,使用Math.max((int) (c.size()/.75f) + 1, 16)计算容量可以防止HashMap扩容,当我们往 HashMap 拷贝大集合时,也可以使用这种方式指定HashMap的初始容量。

TreeSet源码解析

TreeSet 大致的结构和 HashSet 相似,底层组合的是 TreeMap,所以继承了 TreeMap key 能够排序的功能,迭代的时候,也可以按照 key 的排序顺序进行迭代。

TreeSet组合TreeMap的过程中使用了两种方式,如下:

  1. 对于add()这类简单的方法,没有复杂的逻辑,TreeSet直接调用TreeMap的put()方法;
  2. 对于迭代器这类复杂的方法,TreeMap的迭代器并不能满足TreeSet,如果TreeSet自己实现迭代器,由于底层使用的是TreeMap,需要对TreeMap的底层实现特别清楚,难度较大,TreeSet采用的方式是,自己负责接口定义,TreeMap负责具体实现,因为接口是 TreeSet 定义的,所以实现一定是 TreeSet 最想要的;

LinkedHashSet源码解析

LinkedHashSet继承了HashSet,跟HashMap与LinkedHashMap的区别一样,LinkedHashSet中的元素也是有序的,可以通过存放顺序进行遍历,LinkedHashSet之所以有序,是因为LinkedHashSet底层组合的是LinkedHashMap,源码如下:

public LinkedHashSet(int initialCapacity, float loadFactor) {
  super(initialCapacity, loadFactor, true);
}

HashSet(int initialCapacity, float loadFactor, boolean dummy) {
  map = new LinkedHashMap<>(initialCapacity, loadFactor);
}

这种设计思路很巧妙,LinkedHashSet虽然继承的是HashSet,但是通过构造方法改变了底层的数据结构,在LinkedHashSet中只有构造方法,没有定义其他的方法,都是从HashSet继承的。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值