When I read Effective Java item 27, the type casting between UnaryFunction<Object>
and UnaryFunction<T>
confused me.
interface UnaryFunction<T> {
T apply(T t);
}
public class Main {
private static final UnaryFunction<Object> IDENTITY = new UnaryFunction<Object>() {
public Object apply(Object t) {
return t;
}
};
@SuppressWarnings("unchecked")
public static <T> UnaryFunction<T> identityFunction() {
return (UnaryFunction<T>) IDENTITY;
}
public static void main(String ... args) {
UnaryFunction<A> identityA = Main.identityFunction();
A a = identityA.apply(new A());
}
}
class A {}
Why UnaryFunction<Object>
can be casted to UnaryFunction<T>
?
I know the generic type will be erased after complier. So (UnaryFunction<T>) IDENTITY
will eventually be (UnaryFunction<Object>) IDENTITY
, this will be working in Runtime.
But directly casting UnaryFunction<Object>
to UnaryFunction<A>
is not allowed by compiler.
UnaryFunction<A> identityA = (UnaryFunction<A>)IDENTITY;
//incompatible types: UnaryFunction<java.lang.Object> cannot be converted to UnaryFunction<A>
And there is no inheritance relationship between UnaryFunction<Object>
and UnaryFunction<T>
. So why UnaryFunction<Object>
can be casted to UnaryFunction<T>
?
All generic types, without a bound (... extends ...
, is considered Object
due to type erasure. So this cast might be valid for some values of T
. @SuppressWarnings("unchecked")
tells the compiler you are doing the right thing so the warning is suppressed.
Casting to a specific type is problematic. Let's assume you are dealing with List<Object>
which you cast to List<A>
where A
is a class. In this case list might have elements which are a supertype of A
so this cast is unsound hence the compiler does not allow it. In case of the function (UnaryFunction<Object>
) it is implied that this can return an Object. Say your code was IDENTITY = t -> new Object();
in which case casting to UnaryFunction<A>
would be unsound as it returns an Object
. In the case it is UnaryFunction<T>
there is some type T
which satisfies the cast, that is, when T
is an Object
.
For some background reading on this see: Liskov substitution principle which deals with subtyping of functions.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With