Java:强制转换和泛型

Java : casting and generics

提问人:AntonBoarf 提问时间:11/14/2023 更新时间:11/14/2023 访问量:54

问:

我对泛型有一些理解问题

我有这个变量:private static final UnaryOperator<Object> IDENTITY_FN = t -> t;

我不明白为什么这段代码会编译:

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

UnaryOperator<String> fn = identityFunction();

但。。。此代码不编译:

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

对我来说,它看起来基本是一样的

Java 泛型 转换

评论

2赞 Sweeper 11/14/2023
它们不一样。在一种情况下,您正在强制转换为 ,在另一种情况下,您正在强制转换为 。像这样的“为什么”问题并不是真正可以回答的,因为对于我给出的每一个解释,你都可以不停地问“为什么会这样?”我们将永远在这里。您能否描述一下您正在寻找什么样的答案,并展示您已经知道的内容,以便我们有一些共同点?UnaryOperator<T>UnaryOperator<String>
1赞 VGR 11/14/2023
当然,无论如何,没有人应该在实践中这样做。编译器警告说,此类代码不安全是有原因的。大多数类型化的泛型强制转换都是不安全的。总有更好的方法。

答:

0赞 KevinJDK 11/14/2023 #1

我认为在第二个代码片段中,它没有编译,因为强制转换为是不安全的,因此不允许编译。是安全的,因为它使用类型擦除,允许它使用泛型类型。由于类型擦除,投射是安全的。在运行时,Java 类型系统会擦除类型变量 T,并将其替换为其绑定变量或 Object(如果它是无界的)。因此,在运行时,只需 变成 ,并且可以安全地转换为此原始类型。UnaryOperator<String>identityFunction()(UnaryOperator<T>) IDENTITY_FNUnaryOperator<T>UnaryOperatorIDENTITY_FN

当您将结果分配给特定类型的变量(如 )时,Java 编译器会检查这些类型是否兼容。identityFunction()UnaryOperator<String>

1赞 newacct 11/23/2023 #2

在编译时不允许将表达式(类型为 )转换为类型,因为可以证明某些东西不可能同时是 a 和 a(即不能有任何类型是两者的子类型)。泛型类型参数是不变的,因此 虽然是 的子类型,但不是 的子类型,反之亦然。如果一个实现类继承了两次,则不允许在两次继承中使用不同的类型参数继承它。IDENTITY_FNUnaryOperator<Object>UnaryOperator<String>UnaryOperator<Object>UnaryOperator<String>StringObjectUnaryOperator<String>UnaryOperator<Object>UnaryOperator

另一方面,在编译时不允许将 (which has type ) 转换为 type,因为某些东西有可能同时是 a 和 a ——也就是说,如果 是 ,那么将是两者的子类型。尽管此强制转换也可能不正确(即何时是 ),但由于至少有一种情况可能是有效的,编译器不能禁止它。IDENTITY_FNUnaryOperator<Object>UnaryOperator<T>UnaryOperator<Object>UnaryOperator<T>TObjectUnaryOperator<Object>TObject