Q.1)如AbstractSet文档中所述-“此类不会覆盖AbstractCollection
类的任何实现。”如果它不覆盖或更改add(Object o)
或由Collection
类实现的任何其他AbstractCollection
接口协定,则仅继承它们,如HashSet。HashSet
和其他Set
对象如何执行规定,例如没有重复的添加检查或插入元素的哈希表方式,这与List
或其他Collection
对象可以添加元素的方式完全不同。
Q.2)在文档中,对于AbstractSet,它是这样编写的,AbstractSet
仅添加了equals
和hashcode
的实现。但是,在方法详细信息部分中,提到Object
类已经重写了equals
和hashcode
方法。 AbstractSet
仅继承而不对这两个方法做任何更改吗?如果是这样,AbstractSet
类的重要性是什么?请澄清
最佳答案
Q1:HashSet如何执行重复检查?
如果看一下java.util.HashSet中的实现,您将看到以下代码:-
private static final Object PRESENT = new Object();
public boolean add(E e) {
return map.put(e, PRESENT)==null;
}
发生的事情很简单;我们使用私有的HashMap实例,该实例采用我们提供的值并将其插入为HashMap的键。映射的PRESENT值从不实际使用或检索,但它允许我们使用此后备映射来验证项目是否存在于Set中。
如果我们提供的值在地图中不存在,则对map.put()的调用会将该项放置在地图中并返回我们的对象。否则,映射保持不变,并且该方法返回null。 HashMap在这里为HashSet做艰苦的工作。
这与AbstractCollection类提供的实现不同,因此需要重写。
Q2:AbstractSet对equals()和hashCode()的使用
我认为您在某种程度上误解了AbstractSet在做什么。 AbstractSet的目的是提供等于和hashCode的集合安全的实现。
通过验证我们是否正在比较两个Set对象,它们具有相同的大小以及它们包含相同的项目来执行均等检查。
public boolean equals(Object o) {
if (o == this)
return true;
if (!(o instanceof Set))
return false;
Collection<?> c = (Collection<?>) o;
if (c.size() != size())
return false;
try {
return containsAll(c);
} catch (ClassCastException unused) {
return false;
} catch (NullPointerException unused) {
return false;
}
}
hashCode是通过遍历Set实例并迭代哈希每个项而产生的:
public int hashCode() {
int h = 0;
Iterator<E> i = iterator();
while (i.hasNext()) {
E obj = i.next();
if (obj != null)
h += obj.hashCode();
}
return h;
}
从AbstractSet扩展的任何类都将使用equals()和hashCode()的此实现,除非它明确地覆盖了它们。此实现优先于java.lang.Object中定义的默认equals和hashCode方法。