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.