alex
02/12/2019, 4:34 PMString[] a = ...;
Object[] o = a;
o[i] = 42;
To prevent that all generics are invariant:
List<String> s = ...;
List<Object> o = s; // compile error;
but it's very hard constraint.
So language introduced the means to explicitly specify co-/contrvariance, which gives flexibility in some typical situations, but it also forbids you certain set of things, like this:
covariance gives you ability to read, but you can't insert:
List<? extends Number> s = <numbers>;
s.add(<number>);
but you can't
s[0] = <number>;
because of the problem mentioned in the first paragraph (i.e. s
is the list of `double`s and you add
integer
). covariance gives you upper bound, saying that "there can be any class derived from this class/interface".
contrvariance is somewhat opposite. You're free to insert, but you can't read:
List<? super Double> s = <numbers>;
s.remove(0);
you can't read, because you know the lower boundary (Number
), you don't know what kind of other objects might be here (Double -> Number -> Object
).