Search code examples
javainheritancecovariance

Java template inheritance with wildcard


In Java the following code won't compile:

class Pair <T1> { }

class Real {
    Pair<Real> sqrt() { 
        return null;
    }
}
class Complex extends Real { 
    Pair<Complex> sqrt()  {  
        return null;
    }
}

Makes sense, because Pair<Complex> doesn't inherit from Pair<Real>.

However, I was surprised to find out that this code will compile:

class Pair <T1> { }

class Real {
    Pair<? extends Real> sqrt() {
        return null;
    }
}

class Complex extends Real {
    Pair<? extends Complex> sqrt()  {
        return null;
    }
}

This seems to imply that Pair<? extends Complex> does in fact inherit from Pair<? extends Real>

Can someone explain this? What exactly is happening here?


Solution

  • I think the best way to think about it is this:

    You're required in Complex to provide a method that returns something of type Pair<T> where T can be anything that inherits from Real. Your Complex implementation changes the return type requirements to Pair<U> where U can be anything that inherits from Complex.

    However as Complex inherits from Real, anything extending Complex will also extend Real, so you are still providing a method that guarantees a return type of Pair<T>.


    To formalise it a bit:

    Pair<? extends Complex> ≡ Pair<? extends Complex extends Real> ≡ Pair<? extends Real>
    

    The difference in your first example that doesn't compile is that your Complex implementation is actually restricting the return type, as not every Pair<Real> is a Pair<Complex>.