Issue
I've read some articles about Covariance, Contravariance, and Invariance in Java, but I'm confused about them.
I'm using Java 11, and I have a class hierarchy A => B => C
(means that C
is a subtype of B
and A
, and B
is a subtype of A
) and a class Container
:
class Container<T> {
public final T t;
public Container(T t) {
this.t = t;
}
}
for example, if I define a function:
public Container<B> method(Container<B> param){
...
}
here is my confusion, why does the third line compile?
method(new Container<>(new A())); // ERROR
method(new Container<>(new B())); // OK
method(new Container<>(new C())); // OK Why ?, I make a correction, this compiles OK
if in Java Generics are invariant.
When I define something like this:
Container<B> conta = new Container<>(new A()); // ERROR, Its OK!
Container<B> contb = new Container<>(new B()); // OK, Its OK!
Container<B> contc = new Container<>(new C()); // Ok, why ? It's not valid, because they are invariant
Solution
The question's examples don't demonstrate the invariance of generics.
An example which does demonstrate this would be:
ArrayList<Object> ao = new ArrayList<String>(); // does not compile
(You might incorrectly expect the above to compile, because String
is a subclass of Object
.)
The question shows us different ways to construct Container<B>
objects - some of which compile and others which do not, because of the inheritance hierarchy of A
, B
and C
.
That diamond operator <>
means that the created container is of type B
in every case.
If you take the following example:
Container<B> contc = new Container<>(new C()); // compiles
And re-write it by populating the diamond with C
, the you will see that the following does not compile:
Container<B> contc = new Container<C>(new C()); // does not compile
That will give you the same "incompatible types" compilation error as my ArrayList
example.
Answered By - andrewJames
Answer Checked By - Dawn Plyler (JavaFixing Volunteer)