源码分析之HashSet
2017-04-17 本文已影响98人
特立独行的猪手
概念
HashSet
是Java Collections Framework
中Set
接口的一种实现了。HashSet
底层是基于HashMap
来实现的,之前已经分析过HashMap
的源码,这时候再来看HashSet
的源码相对来说是很轻松的。
类结构
HashSet
继承AbstractSet
类,实现了Set
接口。由于HashSet
是用HashMap
实现的,所以HashMap
在数据存储上也是无序的。
类成员
PRESENT
private static final Object PRESENT = new Object();
HashMap
是键值对K-V
模型的,HashSet
则是普通的集合类型。这里的PRESENT
就是用来填充HashMap
中的value
的。
构造函数
HashSet
提供了4种构造函数。
// 默认无参构造函数
public HashSet() {
map = new HashMap<>();
}
// 以现有集合构造
public HashSet(Collection<? extends E> c) {
map = new HashMap<>(Math.max((int) (c.size()/.75f) + 1, 16));
addAll(c);
}
// 带参构造 initialCapacity: 初始大小 loadFactor:加载因子
public HashSet(int initialCapacity, float loadFactor) {
map = new HashMap<>(initialCapacity, loadFactor);
}
// 带参构造 initialCapacity: 初始大小
public HashSet(int initialCapacity) {
map = new HashMap<>(initialCapacity);
}
// 仅用来构造LinkedHashSet使用
HashSet(int initialCapacity, float loadFactor, boolean dummy) {
map = new LinkedHashMap<>(initialCapacity, loadFactor);
}
add 方法
public boolean add(E e) {
return map.put(e, PRESENT)==null;
}
add
方法很简单,直接调用HashMap
的put
方法实现。value
则是用PRESENT
进行填充。
remove 方法
public boolean remove(Object o) {
return map.remove(o)==PRESENT;
}
remove
方法也是同样,调用HashMap
的remove
方法。
...
HashSet
大多数的方法都是通过HashMap
的方法来实现的。
hashCode方法 & equals方法
如果我们在使用HashSet
来存储自定义的对象时候,要记得重写hashCode
方法和equals
方法。我们将通过一个示例来说明重写的必要性。
public class Test {
String a;
public Test(String a) {
this.a = a;
}
public static void main(String[] args) {
Set set = new HashSet();
Test o1 = new Test("abc");
Test o2 = new Test("abc");
set.add(o1);
set.add(o2);
System.out.println(o1.equals(o2));
System.out.println(set.size());
}
上面程序输出应该是:
false
2
默认equals
方法是通过比较引用是否来判断2个对象是否一致的。o1
和o2
显然是2个对象,他们是不相等的,他们各自的hashcode
显然是不同的,所以HashSet
会把他们当做2
个不同对象来处理。
我们想要a
相同的对象都是同一个对象的话,使用默认的equals
和hashcode
方法显然无法满足我们要求的,这时候就需要重写equals
和hashcode
方法。
@Override
public int hashCode() {
return 123 * 31 + a.hashCode();
}
@Override
public boolean equals(Object o) {
Test test = (Test) o;
return test.a.equals(this.a);
}
这里再运行main
的结果就是:
true
1
总结
HashSet
存储元素,是将元素作为HashMap
的key
进行操作,所以不保证元素顺序。HashSet
不会有重复数据,重复数据都被覆盖。