为什么可以在 Java 中使用泛型将对象转换为整数?

Why can an Object be cast as an Integer using generics in Java?

提问人:exhausted 提问时间:5/30/2022 最后编辑:exhausted 更新时间:6/1/2022 访问量:119

问:

我找到了一种通过泛型类型将 Floats 添加到整数数组的方法。我很好奇为什么 Java 在运行时错误中没有捕获到这一点?我尝试浏览文档以获取有关此内容的任何信息,但我没有任何运气。

例如,假设我有两个 ArrayList,一个包含 Integers,另一个包含 Floats,如下所示:

ArrayList<Integer> listInt = new ArrayList<>();
ArrayList<Float> listFlt = new ArrayList<>();
  
listInt.add(6);
listInt.add(71);
  
listFlt.add(4.92f);
listFlt.add(20.5f);

使用泛型,我可以通过如下方法将 Floats 从 listFlt 复制到 listInt 中:

public static <T extends Number, S extends Number> void copy(ArrayList<T> src, ArrayList<S> dest) {
   for (int i = 0; i < src.size(); i++) {
       Object x = src.get(i);
       dest.set(i, (S)x);
   }
}

用以下方式调用它:

ClassName.<Float, Integer>copy(listFlt, listInt);

现在,当我打印 listInt 时,它显示:

4.92
20.5

当涉及泛型时,如何将 Object 转换为整数?listInt 如何存储 Floats?谢谢!

Java 泛型 强制转换 浮点 整数

评论

2赞 John3136 5/30/2022
Integer 是 Number 的子类,Number 可以容纳整数、浮点数、双精度、多头......
2赞 Dawood ibn Kareem 5/30/2022
这是运行时类型擦除。JVM 并不关心您在 .类型参数引起的所有类型检查都是在编译时完成的。ArrayList

答:

8赞 Jesper 5/30/2022 #1

使用泛型,我可以通过这样的方法将 Floats 从 listFlt 复制到 listInt 中

请注意,在此方法中,您正在强制转换为 type 参数:S

dest.set(i, (S)x);

这将在编译时导致未经检查的强制转换警告(您不应忽略!

这是允许的,但由于类型擦除,JVM 将无法在运行时检查是否允许强制转换。

这是堆污染的一个例子:由于 Java 语言和类型擦除的规则,您可能会遇到这样一种情况:您可以将对象添加到错误类型的对象中(在本例中:您正在将对象添加到应该包含对象的列表中)。ArrayListFloatInteger

当你只打印列表时,没有问题,因为在这种情况下,Java 只需要调用列表的元素,并且该方法存在于所有对象中。toString()

但是当你试图从列表中得到一个时,你会得到一个:IntegerClassCastException

ClassName.<Float, Integer>copy(listFlt, listInt);

Integer i = listInt.get(0); // ClassCastException: Float cannot be cast to Integer

这是 Java 规则组合的不幸结果,这些规则在一定程度上是因为向后兼容性,以及 Java 使用泛型(带有类型擦除)的方式。

要记住的一点:不要忽视“未选中的投射”警告;它们暗示代码中可能存在堆污染。

评论

5赞 rzwitserloot 5/30/2022
我想你已经把这个本来很好的答案埋没了:泛型是javac想象力的虚构:运行时不知道它们是什么,因此无法检查任何一个。