Search code examples
javalistinheritancecontravariance

What's the difference between contravariance and inheritance in Java?


I have a parent class A, and its child class B. What is the difference between these two snippets :

    public static void main (String[] args) {
        ArrayList<? super A> e = new ArrayList<>();
        B thing = new B();
        e.add(thing);
        System.out.println(e.get(0));
    }
    public static void main (String[] args) {
        ArrayList<A> e = new ArrayList<>();
        B thing = new B();
        e.add(thing);
        System.out.println(e.get(0));
    }

Solution

  • The difference between ArrayList<? super A> and ArrayList<A> is that the former can be assigned an object of ArrayList<T> where T is a superclass of A or A itself.

    In concrete terms, this is valid:

    ArrayList<? super A> listOfSuperA = new ArrayList<Object>();
    

    This is not:

    ArrayList<A> listOfA = new ArrayList<Object>();
    

    This means that you can get values of different types out of listOfA and listOfSuperA:

    A a = listOfA.get(0); // valid
    Object o = listOfA.get(0); // valid, because A can be converted to Object.
    A a2 = listOfSuperA.get(0); // invalid, because listOfSuperA could contain Objects, which are not convertible to A
    Object o2 = listOfSuperA.get(0); // valid, because whatever is in listOfSuperA, it can be converted to Object
    

    This might be useful if you want to learn more about where to use ? super T