创建扩展Hashset / Inheritance的计数类

时间:2013-05-07 19:11:31

标签: java collections hashset

如果我们考虑以下类来计算在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 method? (这就是为什么我得到15而不是10)

2 个答案:

答案 0 :(得分:5)

你将继承视为组合。不是。这些电话不会在add()上“HashSet” - 它们最终会在当前对象上显示“add()”。

  

但为什么super.addAll(c)调用我重新定义的add方法?

因为这就是虚拟方法的行为方式。 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()并不意味着该对象突然处于“非重写”模式或类似的任何模式。

答案 1 :(得分:1)

多态性是如何工作的。您的对象属于CountingHashSet类型,因此对add的调用将调用CountingHashSet.add,即使是超级类型也是如此。