1 概述
前面的文章,我们分析了List和Map的一些实现类。现在我们开始分析Set的实现类。
Set和List相同都是用于存放数据的集合,不同的是Set中的元素不允许重复(通过hashCode和equals函数来保证不重复性),如果数据相同就会进行覆盖。
Set的实现是依赖于Map的实现,我们知道Map中的key也是不允许重复的。接下来我们就来看一下Set的具体实现类HashMap的实现吧。
2 属性
//用户存放想HashSet中插入的数据
private transient HashMap<E,Object> map;
//插入的HashMap中的key对应的虚拟值
private static final Object PRESENT = new Object();
HashSet的属性也体现了HashSet是依赖HashMap进行数据的存储的。
3 构造函数
这里我们仅仅看一个比较常规的构造函数。
public HashSet(int initialCapacity, float loadFactor) {
map = new HashMap<>(initialCapacity, loadFactor);
}
从上面的代码我们可以看出,HashSet的初始化其实就是初始化它的数据存储属性map。
4 核心函数
我们查看一下HashSet的源码就可以发现,HashSet的方法的实现基本都是直接依赖于HashMap的相应方法。下面我们来看一下添加数据的方法add。
public boolean add(E e) {
//直接调用map中的put方法,插入的值为PRESENT,键为e,如果之前就存在对应的键,就返回false。
return map.put(e, PRESENT)==null;
}
明显,上面的add方法就是直接调用的HashMap的put方法。如果put有返回值,说明已经存在对应的值在HashSet中,所以这个时候插入失败,返回false。
5 总结
HashSet的实现原理比较简单,其实就是依靠HashMap中键的特性来实现的。并且针对值得操作其实就是操作HashMap中的键,而HashMap中的值就是统一的new Object()。
在此,我们需要注意的是HashSet中并没有根据索引来获取值的方法,这也是由于HashMap的特性导致的,所以如果我们要遍历HashSet,就只能使用迭代器或者增强型for循环。