JDK源码分析——HashSet

引:如果用来有个去重的需求,你肯定会想到用HashSet,那我们看看它的实现!

详细注释:源码分析地址

概览

它是由哈希表(实际上是一个HashMap实例)支持,是不是有点意思?它不保证set的迭代顺序,有且只允许一个null元素,当然其他元素不能重复。

它不是同步容器。如果多个线程同时访问一个哈希set,而其中至少一个线程修改了该 set,那么它必须保持外部同步。这通常是通过对自然封装该set的对象执行同步操作来完成的。如果不存在这样的对象,则应该使用 Collections.synchronizedSet 方法来“包装” set。最好在创建时完成这一操作,以防止对该set进行意外的不同步访问。

所有这个类的方法返回的迭代器都是快速失败的 :如果映射在迭代器创建之后的任何时间被结构地修改,除了通过迭代器自己的remove方法之外,迭代器将抛出一个ConcurrentModificationException。(老生长谈)

构造

关于HashSet的操作(下面都是),基本上都是直接调用底层HashMap的相关方法来完成。所以在后面参考找到自己关于HashMap的文章。

1
2
3
4
5
6
7
8
9
// 真的操作的执行者
private transient HashMap<E,Object> map;
// 定义一个"虚拟"的Object对象作为HashMap的value
private static final Object PRESENT = new Object();

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

在HashMap新增一个键值对

1
2
3
public boolean add(E e) {
return map.put(e, PRESENT)==null;
}

在HashMap删除一个键值对

1
2
3
public boolean remove(Object o) {
return map.remove(o)==PRESENT;
}

在HashMap查找key是否存在

1
2
3
public boolean contains(Object o) {
return map.containsKey(o);
}

总结

水文一篇,只要记住一点,就是只要理解了HashMap,HashSet is so easy!!

参考

  1. JDK源码分析——HashMap