【源码阅读】HashSet 和 LinkedHashSet 1.8

HashSet、LinkedHashSet 两个类是在 HashMap / LinkedHashMap 的基础上组装起来的类,因此本文侧重:java

  • 为何要组合 HashMap / LinkedHashMap?
  • 如何组合 HashMap / LinkedHashMap?

1、什么是 HashSet ?

  • 线程不安全
  • 底层实现基于 HashMap
  • 迭代过程当中,若是数据被修改,会产生快速失败。

1. 成员变量

public class HashSet<E> extends AbstractSet<E> implements Set<E>, Cloneable, java.io.Serializable {
    ...
    // 键值Map
    private transient HashMap<E,Object> map;
    // 用做全部键对应的值,键所对应的值都相等
    private static final Object PRESENT = new Object();
    ...
}

Q1:为何要组合 HashMap 而不继承 HashMap?安全

  • 继承表示父子类是同一类事物,而 Set 和 Map 原本就是想表达两类事物,因此用继承欠妥,并且 java 只支持单继承,可扩展性不强。
  • 组合更加灵活,能够任意的组合现有的基础类,而且能够在基础类方法的基础上进行扩展。

2. 构造方法

// 调用的是HashMap的构造方法
public HashSet() {
    map = new HashMap<>();
}
public HashSet(int initialCapacity, float loadFactor) {
    map = new HashMap<>(initialCapacity, loadFactor);
}

public HashSet(int initialCapacity) {
    map = new HashMap<>(initialCapacity);
}

public HashSet(Collection<? extends E> c) {
    map = new HashMap<>(Math.max((int) (c.size()/.75f) + 1, 16));
    addAll(c);
}

Math.max ((int) (c.size ()/.75f) + 1, 16),对 HashMap 的容量进行了计算:线程

  • HashMap 的阈值计算:Map 的容量 * 0.75f
  • 若是给定 HashMap 初始容量小于 16 ,就按照 HashMap 默 认的 16 初始化

Q:往 HashMap 里拷贝大集合时,如何给 HashMap 初始化大小?code

  • A:借鉴上述初始化思路:max(指望值 / 0.75 + 1,默认值 16)

2、什么是 LinkedHashSet?

  • LinkedHashSet 是具备可预知迭代顺序的 Set 接口的哈希表和连接列表实现。
  • LinkedHashSet 内部维护着一条双向列表,此连接列表定义了迭代顺序,可为插入顺序或是访问顺序。
  • LinkedHashSet 里面有一个 LinkedHashMap (适配器模式),对 LinkedHashSet 的方法调用都会转换成合适的 LinkedHashMap 方法。
public class LinkedHashSet<E> extends HashSet<E> implements Set<E>, Cloneable, java.io.Serializable {
    ...
    public LinkedHashSet(int initialCapacity, float loadFactor) {
        map = new LinkedHashMap<>(initialCapacity, loadFactor);
    }
    ...
    public boolean add(E e) {
        return map.put(e, PRESENT)==null;
    }
    ...
}
相关文章
相关标签/搜索