HashSet源码分析
HashSet是Set的一个实现,Set定义一个集合,集合的一个特征是不能包含重复的元素(可以包含null),HashSet底层使用HashMap作为存储结构来实现。
可知HashSet只用来存储对象,并不是key-value对,因为HashMap中的key必须是不同的,跟集合的定义相同,
所以HashSet只使用HashMap中的key来存储元素,而value字段使用同一个常量对象PRESENT就可以了。
private static final Object PRESENT = new Object();
private transient HashMap<E,Object> map;
可知HashSet中判断将要被存储的元素是否已经存在集合中,被转移到HashMap中判断key值是否有重复,而key的判断逻辑如下:
//x,y是两个key
static boolean eq(Object x, Object y) {
return x == y || x.equals(y);
}
那么到底要不要重写HashSet中对象的equals()方法呢?个人认为这个还是需要根据具体应用需求来决定,默认情况下equals()实现就是比较(x == y),重写以后就是比较两对象的属性值是否相等。
如果应用场景认为,两个对象相同的条件是指向同一个引用,就不需要重写equals()方法了。
如果应用场景认为,两个对象相同的条件是指内部属性值相同,就需要重写equals()方法了。
构造函数
//可知HashSet只用来存储对象,并不是key-value对,因为HashMap中的key必须是不同的,跟集合的定义
//相同,所以HashSet只使用HashMap中的key来存储元素,而value字段使用一个final Object PRESENT就可以
public HashSet() {
map = new HashMap<E,Object>();
}
//构造函数中指定底层HashMap的initialCapacity和loadFactor
public HashSet(int initialCapacity, float loadFactor) {
map = new HashMap<E,Object>(initialCapacity, loadFactor);
}
public HashSet(int initialCapacity) {
map = new HashMap<E,Object>(initialCapacity);
}
add()方法
public boolean add(E o) {
//value值为PRESENT对象,一个常量对象
return map.put(o, PRESENT)==null;
}
remove()方法
public boolean remove(Object o) {
//map.remove(o)可能返回null,那就表示不存在目标Object o
//删除失败
return map.remove(o)==PRESENT;
}
contains()方法
public boolean contains(Object o) {
//到HashMap的Key中去查找目标对象O
return map.containsKey(o);
}
Iterator
//HashSet自己没有实现Iterator接口,而使用HashMap的实现
public Iterator<E> iterator() {
return map.keySet().iterator();
}