网上有许多讲解HashMap与HashSet区别的文章,看了下感觉有点空,自己去查看了源代码,发现区别似乎不大。
HashSet继承了AbstractSet<E>,并且实现了Set<E>,Cloneable,Serializable接口。有一点要注意的是,在HashSet中创建了一个HashMap实例,并且,HashSet的三个构造方法都是直接初始化HashMap。
public HashSet() {
map = new HashMap<>();
}
public HashSet(Collection<? extends E> c) {
map = new HashMap<>(Math.max((int) (c.size()/.75f) + 1, 16));
addAll(c);
}
public HashSet(int initialCapacity, float loadFactor) {
map = new HashMap<>(initialCapacity, loadFactor);
}
后续方法也是与HashMap紧密相关,由此应该可以说HashSet是建立在HashMap的基础上运作的。接下来看下HashMap的源代码,继承AbstractMap类,实现的接口是Map,Cloneable,Serizlizable,有差别,也有共同点。感觉真要说清楚是不是应该看看Abstract前缀的那两个类?
HashSet是如何实现“不允许集合中有重复值的”?
/**
* Adds the specified element to this set if it is not already present.
* More formally, adds the specified element <tt>e</tt> to this set if
* this set contains no element <tt>e2</tt> such that
* <tt>(e==null ? e2==null : e.equals(e2))</tt>.
* If this set already contains the element, the call leaves the set
* unchanged and returns <tt>false</tt>.
*
* @param e element to be added to this set
* @return <tt>true</tt> if this set did not already contain the specified
* element
*/
public boolean add(E e) {
return map.put(e, PRESENT)==null;
}
看上面的注释知道这个方法帮我们实现了,然而实际上它也只是用了HashMap.put(E key, Object value)来判断,根据key来判断值是否已存在。从传入的参数看,貌似HashSet添加的值e是在HashMap的key位置上,而HashMap是不允许key重复的,这不是刚好吗!
个人觉得HashSet就是捡便宜的,大部分工作都是让HashMap做了。当然这只是粗略地讲,毕竟我也没怎么常用这两个,要区分特性还真是不太容易,咳咳。。。