当我阅读有效的Java 项目27时,UnaryFunction<Object>UnaryFunction<T>之间的类型转换使我感到困惑。

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 {}

为什么可以将UnaryFunction<Object>强制转换为UnaryFunction<T>

我知道通用类型将在编译器后删除。因此(UnaryFunction<T>) IDENTITY最终将是(UnaryFunction<Object>) IDENTITY,它将在运行时中运行。

但是编译器不允许直接将UnaryFunction<Object>转换为UnaryFunction<A>
UnaryFunction<A> identityA = (UnaryFunction<A>)IDENTITY;
//incompatible types: UnaryFunction<java.lang.Object> cannot be converted to UnaryFunction<A>

而且UnaryFunction<Object>UnaryFunction<T>之间没有继承关系。那么为什么可以将UnaryFunction<Object>强制转换为UnaryFunction<T>

最佳答案

由于类型擦除,所有无限制的通用类型(... extends ...都被视为Object。因此,此强制转换可能对T的某些值有效。 @SuppressWarnings("unchecked") 告诉编译器您在做正确的事情,因此该警告被禁止。

强制转换为特定类型是有问题的。假设您要处理的List<Object>转换为List<A>,其中A是一个类。在这种情况下,list可能具有A的父类(super class)型的元素,因此这种转换是不正确的,因此编译器不允许这样做。如果是函数(UnaryFunction<Object>),则暗示它可以返回一个Object。假设您的代码是IDENTITY = t -> new Object();,在这种情况下,由于返回UnaryFunction<A>,因此对Object的转换会不正确。在UnaryFunction<T>的情况下,存在某种类型的T可以满足转换要求,即TObject时。

有关此内容的一些背景知识,请参见:Liskov substitution principle,它处理函数的子类型化。

10-05 21:35