【问题标题】:Confusion with type erasure rule in Java Generics与 Java 泛型中的类型擦除规则混淆
【发布时间】:2012-08-08 11:19:01
【问题描述】:

我已经研究泛型一个小时了,我有一些疑问。假设我有这样的课程:

class Pair<T>
{
       public T getFirst() { return first; }
}

基本上我的书是这样说的:

类型擦除:类型变量被擦除并替换为它们的边界类型(或 无边界变量的对象。)

所以根据我的书的说法,JVM中的代码应该是这样的:

 class Pair
    {
           public Object getFirst() { return first; }
    }

现在如果我这样做:

   Pair<String> pair = new Pair<>(); //I use Java 7 diamond syntax here.
   pair.getFirst()

我的代码是否需要再次从Object 转换为String 以返回getFirst 类型?

现在考虑:

ArrayList<String> files = new ArrayList<>();

同一本书说的(相对于上面的代码是):

....the files contain array of Strings.

对于上面ArrayList 的示例,我对类型擦除规则感到非常困惑。在这种情况下,files 数组怎么会知道它有 String 数组? (这与类型擦除规则相矛盾)

编辑:

为了查看Pair 的结果代码(这就是类型擦除发生的方式),我如何在此处使用javap 工具?

我在这里遗漏了什么吗?

【问题讨论】:

  • 在运行时,文件数组不知道它包含字符串,但编译器在编译时知道。
  • @MattR 看到它在编译时知道,它必须在运行时知道。两者之间信息不丢失
  • 编译器可能会被欺骗接受不同类型的数组,并且只有当您尝试从数组中获取元素时才会出现异常。检查此以获取更多详细信息:stackoverflow.com/q/11610421/1384984
  • @James 类型已被删除,因此如果您愿意,可以称其为“丢失”:-) 它是一个对象数组,但如果它在运行时不包含字符串,则确实会引发异常
  • “编译器可能被欺骗接受不同类型的数组” 。

标签: java generics


【解决方案1】:

您的困惑来自编译器的作用和 JVM 的作用。

Pair<String> pair = new Pair<>(); //I use Java 7 diamond syntax here.
String first = pair.getFirst();

在JVM中等价于

Pair pair = new Pair(); 
String first = (String) pair.getFirst();

在 Map.get() 的情况下

Map<Key, Value> map = ...
Value value = map.get(key);

在JVM中

Map map = ...
Value value = (Value) map.get(key);

那我的代码又需要在 getFirst 的返回类型中从 Object 转换为 String 吗?

没有发生转换。对象没有改变。所发生的只是可能会对引用进行强制检查。

为了查看 Pair 的结果代码(这就是类型擦除发生的方式),我如何在这里使用 javap 工具?

使用javap -c -classpath . ClassUsingPair

【讨论】:

  • 所以在你的第一个代码示例中pair.getFirst(); 应该返回String 类型,那么为什么需要强制转换?
  • pair.getFirst() 总是在类型擦除之后返回一个对象。您必须考虑编译器如何编译代码和JVM如何看待字节码的差异。
  • 哦!我明白了。我的最后一个问题是人们说类型转换总是很困难。但在引擎盖下通用也是如此。那不是很糟糕吗?
  • 不太一样。返回值有一个强制转换。它为您添加样板代码,否则您可能不得不编写哪个更好。
  • 类型转换很难正确处理,如果这意味着编译器可以为您完成大部分工作并在编译时正确处理而不是抛出运行时异常,那就是一种改进。跨度>
【解决方案2】:

1. Erasure 是一个过程,其中编译器在编译期间从类和方法、变量等中删除 Type parameterType arguments。 .

2. Box 变成 Box,这称为 raw-typeRaw-type 是泛型类或接口名称将没有类型参数的一种.

3.所以在运行时找不到泛型...主要是为了让没有使用泛型的代码运行起来没有任何问题 strong>,主要是泛型出现之前编写的那些。

4. Generic Class 不会被实例化,因为它需要初始化它的构造函数,而这不会发生,因为原始 Type 参数在运行时不会存在。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2017-07-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-12-07
    相关资源
    最近更新 更多