In Java, arrays are covariant and generics are invariant.
Yes for arrays. For Java, it is right for generics without wildcard but generics with wildcard goes over that limitation.
What is the point of having array covariant if run time will be NOT
ok?
No value. It is an array specific drawback that was not reproduced such as in generics.
What is the point of all of this?
About Java generics, the thing is that these are not absolutely invariant, covariant or contravariant because the invariant is the safer way but it is also the most restrictive in terms of programming features. I illustrate below.
So Java (as well as other strong typed languages) made the choice to provide distinct generics flavors : invariant, covariant and contravariant while ensuring the type safety in any case (while you respect compiler warnings of course).
But amazingly, there's a way to make generics covariant/cotravariant,
use wildcard:
Not really amazing.
Without covariance, you lose all possibilities to pass a variable declared with generic type in a method that accepts a supertype of this variable. If this method does only reading on the generic variable that is passed as parameter and that the compiler can ensure that : you have no type storing issue at runtime since you don't add anything in it. So you want to use an upper bounded wildcard.
List<Integer> integers = ...;
List<Long> longs = ...;
List<Float> floats = ...;
doThat(integers); // compile ok
doThat(longs); // compile ok
doThat(floats); // compile ok
//...
public void doThat(List<? extends Number> list){
for (Number n : list){ // compile ok : reading
//...
}
// but the compiler doesn't allow to store
list.add(Integer.valueOf(1));
}
Similarly without contravariance you lose all possibilities to add safely things in a generic type. If the compiler ensures that the contravariance is safe because we can only add supertype things in the generic type variable passed to , why do you want to lose this ability ? So you want to use a lower bounded wildcard.
List<Integer> integers = ...;
List<Long> longs = ...;
List<Float> floats = ...;
List<Number> numbers = ...;
doThat(integers); // compile ok
doThat(numbers); // compile ok
doThat(longs); // compile fails
doThat(floats); // compile fails
//...
public void doThat(List<? super Integer> list){
// the compiler allows to add that as type safe
list.add(Integer.valueOf(1));
// but it doesn't allow to add no safe things
list.add(Float.valueOf(1f));
}