如果我们考虑以下类来计算添加到 HashSet 中的对象:
public class CountingHashSet<E> extends HashSet<E> {
public int addCount = 0;
@Override
public boolean add(E e) {
addCount +=1;
return super.add(e);
}
@Override
public boolean addAll(Collection<?
extends E> c) {
addCount += c.size();
return super.addAll(c);
}
然后,JUnit 测试失败了:
@Test
public void testCount() {
CountingHashSet<Integer> s = new CountingHashSet<>();
s.addAll(Arrays.asList(1, 2, 3, 4, 5));
for (int i = 6; i <= 10; ++i)
s.add(i);
assertEquals(10, s.addCount);
}
我得到以下信息:
java.lang.AssertionError: expected:<10> but was <15>
为什么我得到 15?在我看来,s.addAll(myCollection)
调用 super.addAll(c)
,如果我查看 hashSet
的源代码,我看到addAll(c)
调用 add(e)
来添加每个元素。但是为什么super.addAll(c)
调用我重新定义的add方法
呢? (这就是为什么我得到 15 而不是 10)
最佳答案
您将继承视为组合。它不是。调用最终不是“HashSet
上的add()
”——它们最终是“当前对象上的add()
” ".
But why super.addAll(c) call the add method that I redefined ?
因为这就是虚拟方法的行为方式。 addAll
只是调用 add()
,它将使用实际类型中最重写的实现。这就是多态性总是 的工作原理。让我们写一个更简单的例子:
class Superclass {
public void foo() {
bar();
}
public void bar() {
System.out.println("Superclass.bar()");
}
}
class Subclass extends Superclass {
@Override
public void bar() {
System.out.println("Subclass.bar()");
}
}
public class Test {
public static void main(String [] args) {
Superclass x = new Subclass();
x.foo(); // Prints Subclass.bar()
}
}
Subclass.bar()
的结果是您期望从此示例中得到的结果吗?如果是这样,您认为您的版本会有什么不同?仅仅因为您正在调用 super.addAll()
并不意味着该对象突然处于“非覆盖”模式或类似模式。
关于java - 创建扩展哈希集/继承的计数类,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16426752/