javagenericscasting

Java : casting and generics


I have some understanding issue with generics

I have this variable : private static final UnaryOperator<Object> IDENTITY_FN = t -> t;

I don't understand why this code compiles :

public static <T> UnaryOperator<T> identityFunction() {
        return (UnaryOperator<T>) IDENTITY_FN;
    }

UnaryOperator<String> fn = identityFunction();

But... this code doesn't compile :

UnaryOperator<String> fn = (UnaryOperator<String>) IDENTITY_FN;

It looks basically the same for me


Solution

  • The cast of the expression IDENTITY_FN (which has type UnaryOperator<Object>) to type UnaryOperator<String> is disallowed at compile time because it is provably impossible for something to be both a UnaryOperator<Object> and a UnaryOperator<String> at the same time (i.e. there cannot be any type that is a subtype of both). Generic type arguments are invariant, so although String is a subtype of Object, UnaryOperator<String> is not a subtype of UnaryOperator<Object>, nor vice versa. And if an implementing class inherits from UnaryOperator twice, it is not allowed to inherit it with different type arguments in the two inheritances.

    On the other hand, the cast of IDENTITY_FN (which has type UnaryOperator<Object>) to type UnaryOperator<T> is not disallowed at compile time, because it is possible for something to be a UnaryOperator<Object> and a UnaryOperator<T> at the same time -- namely, if T were Object, then UnaryOperator<Object> would be a subtype of both. Although it's also possible for this cast to be incorrect (i.e. when T is anything other than Object), since there is at least one case where it could be valid, the compiler cannot disallow it.