为什么UnaryFunction<Object>可以转换为UnaryFunction<T>?

5

当我读到《Effective 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>


不相关的 - “identity”在“d”之前没有“n”。 - user2357112
1
T 可以是 ObjectA 绝对不是。 - user2357112
1
@AlexanderKulyakhtin:继承并不足够。A 不是 Object,因此 UnaryFunction<Object> 不能成为 UnaryFunction<A>T 实际上可以是 Object - user2357112
@RobinHan:基本上是这样的。如果你加入了一个类型边界,比如 T extends Integer,那么 T 肯定不是 Object,编译器就会拒绝该转换。 - user2357112
@RobinHan:编译失败了。 你一定是搞砸了你的测试。 - user2357112
显示剩余7条评论
1个回答

5

所有没有限制的泛型(即不带... extends ...),由于类型擦除,被视为Object。因此,这种转换对于某些T的值可能是有效的。@SuppressWarnings("unchecked")告诉编译器你正在做正确的事情,因此警告被禁止。

将特定类型转换可能会出现问题。假设您正在处理 List<Object>,您将其转换为 List<A>,其中 A 是一个类。在这种情况下,列表可能具有作为 A 超类型的元素,因此此转换是不安全的,编译器不允许它。在函数的情况下 (UnaryFunction<Object>),它暗示着可以返回一个对象。如果您的代码是 IDENTITY = t -> new Object();,那么转换为 UnaryFunction<A> 将是不安全的,因为它返回一个 Object。如果是 UnaryFunction<T>,则存在一些类型 T 满足转换,即当 TObject 时。
有关此内容的背景阅读,请参见:Liskov 替换原则,该原则涉及函数的子类型化。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接