Search code examples
javainheritance

Java inheritance vs initialization


I'm reading J. Bloch's Effective Java and now I'm at inheritance vs composition section. As far as I understood he said that inheritance is not always good.

A related cause of fragility in subclasses is that their superclass can acquire new methods in subsequent releases. Suppose a program depends for its security on the fact that all elements inserted into some collection satisfy some predicate. This can be guaranteed by subclassing the collection and overriding each method capable of adding an element to ensure that the predicate is satisfied before adding the element. This works fine until a new method capable of inserting an element is added to the superclass in a subsequent release.

But why doesn't it work? The superclass is just the Collection interface and if we add a new method we just a compile-time error. That's not harmful ever...


Solution

  • Suppose you have a Collection superclass in some library v1.0:

    public class MyCollection {
        public void add(String s) {
            // add to inner array
        }
    }
    

    You subclass it in order to only accept Strings that have length 5:

    public class LimitedLengthCollection extends MyCollection {
        @Override
        public void add(String s) {
            if (s.length() == 5) {
                super.add(s);
            }
        }
    }
    

    The contract, the invariant of this class is that it will never contain a String that doesn't have length 5.

    Now version 2.0 of the library is released, and you start using it. The base class is modified to:

    public class MyCollection {
        public void add(String s) {
            // add to inner array
        }
    
        public void addMany(String[] s) {
            // iterate on each element and add it to inner array
        }
    }
    

    and your subclass is left unmodified. Now users of your subclass can do

    LimitedLengthCollection c = new LimitedLengthCollection();
    c.addMany(new String[] {"a", "b", "c"});
    

    and the contract of your subclass is thus broken. It was supposed to only accept Strings of length 5, and it doesn't anymore, because an additional method has been added in the superclass.