the following is taken from joshua bloch's effective java. pg 82:

public class InstrumentedHashSet<E> extends HashSet<E> {
    // The number of attempted element insertions
    private int addCount = 0;
    public InstrumentedHashSet() {
    }
    public InstrumentedHashSet(int initCap, float loadFactor) {
        super(initCap, loadFactor);
    }
    @Override public boolean add(E e) {
        addCount++;
        return super.add(e);
    }
    @Override public boolean addAll(Collection<? extends E> c) {
        addCount += c.size();
        return super.addAll(c);
    }
    public int getAddCount() {
        return addCount;
    }
}

my question is that how come super.addAll() invokes the overridden add() method instead of the add() method of the supeclass? the book says that doing this :

InstrumentedHashSet<String> s = new InstrumentedHashSet<String>();
s.addAll(Arrays.asList("Snap", "Crackle", "Pop"));

would give count result as 6 instead of 3 , as the count is first incremented in the overridden addAll() method , then super.addAll() invokes the overridden add() method where the counts are incremented again. i dont understand why the overridden add() gets invoked like this. also , i read the docs about addAll() , the only info it has about the linked add() method is this

Note that this implementation will throw an UnsupportedOperationException unless add is overridden (assuming the specified collection is non-empty).

this also , i felt was a little tight on info... asleast to less expirienced programmers...

Recommended Answers

All 3 Replies

Calls to instance methods are resolved at run time, so when you call addAll or add from an instance of InstrumentedHashSet the JVM looks for versions defined in InstrumentedHashSet, and only looks for them in HashSet if they are not overridden in InstrumentedHashSet (unless you explictly use the super keywod which makes the JVM start looking for the method in the current objects superclass).

Don't worry too much about the addAll doc - addAll is defined in java.util.AbstractCollection, which does not have a proper implementation of add, it just throws the unsupported exception. When you subclass java.util.AbstractCollection with a non-abstract class you will have a real add method, so everything is OK.

The add documentation for AbstractCollection is actually rather shameful. When a class is designed to be extended the documentation should go far beyond merely explaining what each method does. A few preconditions and postconditions are fine documentation for a final method, but someone who is overriding a method also needs to know when and why that method will be called.

For example, the documentation for the paint method of java.awt.Component explains that it is called every time the component should be painted, which is critical information for creating custom AWT components. Providing that in the documentation is the sort of thoughtfulness that might allow someone to learn to use AWT without relying on tutorials.

Similarly, the problem with InstrumentedHashSet is caused by a failure of documentation of add which should explain to anyone overriding add that it would be called for each element of any collection given to addAll. The addAll documentation might also mention that, but it isn't as critical since InstrumentedHashSet wouldn't have a problem if it only overrode addAll and only expected addAlls to be counted; those sorts of implementation details are only important to someone who is overriding add, so that's the documentation where it should be explained.

That sort of carelessness means that it is often wise to browse the source code for any class you intend to extend. It seems that you can never depend on documentation to give you all the important information, and java.util is an example of unusually complete documentation, unfortunately.

had some exams going.. sorry for the late reply.

Calls to instance methods are resolved at run time, so when you call addAll or add from an instance of InstrumentedHashSet the JVM looks for versions defined in InstrumentedHashSet, and only looks for them in HashSet if they are not overridden in InstrumentedHashSet (unless you explictly use the super keywod which makes the JVM start looking for the method in the current objects superclass).

thanks for pointing this out. i dont think i read about this anywhere, and even if i did , forgot it completely. ran the code with some debug prints , it makes more sense now. :)

should explain to anyone overriding add that it would be called for each element of any collection given to addAll.

yes! had it not been mentioned in the book , that little one liner on the addAll() documentation about it throwing an UnsupportedOperationException unless add() had an override, would not have been enough for me to understand that addAll() calls add() from inside of it.. it would have been better if the documentations had mentioned these facts more clearly.

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.