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

exh*_*ted 5 java generics floating-point integer casting

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

例如,假设我有两个 ArrayList,一个包含整数,一个包含浮点数,如下所示:

ArrayList<Integer> listInt = new ArrayList<>();
ArrayList<Float> listFlt = new ArrayList<>();
  
listInt.add(6);
listInt.add(71);
  
listFlt.add(4.92f);
listFlt.add(20.5f);
Run Code Online (Sandbox Code Playgroud)

使用泛型,我可以通过如下方法将浮点数从 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);
   }
}
Run Code Online (Sandbox Code Playgroud)

调用它:

ClassName.<Float, Integer>copy(listFlt, listInt);
Run Code Online (Sandbox Code Playgroud)

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

4.92
20.5
Run Code Online (Sandbox Code Playgroud)

当涉及泛型时,如何将对象转换为整数?那么listInt如何存储Floats呢?谢谢!

Jes*_*per 8

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

请注意,在此方法中,您正在转换为类型参数S:

dest.set(i, (S)x);
Run Code Online (Sandbox Code Playgroud)

当您编译它时,这将导致未经检查的强制转换警告(您不应该忽略它!)。

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

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

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

但是当你尝试Integer从列表中删除一个时,你会得到一个ClassCastException:

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

Integer i = listInt.get(0); // ClassCastException: Float cannot be cast to Integer
Run Code Online (Sandbox Code Playgroud)

这是 Java 规则(部分是由于向后兼容性)和 Java 处理泛型(类型擦除)的方式结合在一起的不幸结果。

要记住的一点:不要忽略“uncheckedcast”警告;它们暗示您的代码中可能存在堆污染。

  • 我认为你已经把这个本来很好的答案埋葬了:__泛型是`javac`想象力的虚构__:运行时不知道它们是什么,因此无法检查它们。 (5认同)