user2336315
user2336315

Reputation: 16067

Create counting class extending Hashset / Inheritance

If we consider the following class to count object added in an 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);
    }

}

Then, the JUnit test failed :

@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);
}

I get the following :

java.lang.AssertionError: expected:<10> but was <15>

Why I get 15 ? To my mind s.addAll(myCollection) call super.addAll(c) and if I look into the source code of hashSet, I saw that addAll(c) call add(e) to add each element. But why super.addAll(c) call the add method that I redefined ? (that's why I get 15 instead of 10)

Upvotes: 1

Views: 2336

Answers (2)

Jon Skeet
Jon Skeet

Reputation: 1502106

You're treating inheritance as if it were composition. It's not. The calls don't end up being "add() on the HashSet" - they end up being "add() on the current object".

But why super.addAll(c) call the add method that I redefined ?

Because that's how virtual methods behave. addAll just calls add(), which will use the most overridden implementation in the actual type. That's how polymorphism always works. Let's write a simpler example:

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()
    }
}

Is the result of Subclass.bar() what you'd expect from this example? If so, what do you expect the difference would be in your version? Just because you're calling super.addAll() doesn't mean that the object is suddenly in "non-overriding" mode or anything like that.

Upvotes: 5

Vincent van der Weele
Vincent van der Weele

Reputation: 13177

That's how polymorphism works. Your object is of type CountingHashSet, so a call to add will call CountingHashSet.add, even from the super type.

Upvotes: 1

Related Questions