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?
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>
.