My understanding is generic types are invariant, so if we have B as a subtype of A, then List<B> has no relationship with List<A>. So casting won't work on List<A> and List<B>.
From Effective Java Third Edition we have this snippet of code:
// Generic singleton factory pattern
private static UnaryOperator<Object> IDENTIFY_FN = (t) -> t;
@SuppressWarnings("unchecked")
public static <T> UnaryOperator<T> identifyFunction() {
return (UnaryOperator<T>) IDENTIFY_FN; //OK But how, why?
}
public static void main(String[] args) {
String[] strings = {"a", "b", "c"};
UnaryOperator<String> sameString = identifyFunction();
for (String s : strings) {
System.out.println(sameString.apply(s));
}
}
Here I am confused. We have cast IDENTIFY_FN, whose type is UnaryOperator<Object>, to UnaryOperator<T>, which has another type parameter.
When type erasure happens String is a subtype of Object, but so far as I know UnaryOperator<String> is not a subtype of UnaryOperator<Object>.
Do Object and T relate somehow? And how does casting succeed in this case?
Generics don't exist at runtime. At runtime, every
UnaryOperator<T>is aUnaryOperator<Object>. The cast is necessary to placate the compiler at compile-time. At runtime it's meaningless.