【问题标题】:Java type erasure - why can I see the type when I look at the bytecode?Java 类型擦除 - 为什么在查看字节码时可以看到类型?
【发布时间】:2016-03-17 10:44:48
【问题描述】:

我试图理解为什么不允许在一个类中同时编写这两种方法

 public bool plus(List<String>) {return true;}
 public bool plus(List<Integer>) {return true;}

我试图弄清楚它与类型擦除的关系,但是当我反编译以下代码时

public class Test<T> {

   boolean plus2(List<T> ss) {return false;}
   boolean plus(List<String> ss) {return false;}
   boolean plus(Set<Integer> ss) {return false;}
}

当我用Java反编译器(jd)反编译它时,我得到了同样的结果

即使我打印字节码,我也可以清楚地看到类型。
(查看 SO answer 声明“但请确保类型在字节码中被删除”)

    Compiled from "Test.java"
    public class com.example.Test<T> {
    public com.example.Test();
            Code:
            0: aload_0
            1: invokespecial #1                  // Method java/lang/Object."<init>":()V
            4: return

            boolean plus2(java.util.List<T>);
            Code:
            0: iconst_0
            1: ireturn

            boolean plus(java.util.List<java.lang.String>);
            Code:
            0: iconst_0
            1: ireturn

            boolean plus(java.util.Set<java.lang.Integer>);
            Code:
            0: iconst_0
            1: ireturn
            }

【问题讨论】:

    标签: java java-8 type-erasure


    【解决方案1】:

    您的编译器需要能够根据字节码中的信息检查泛型类型信息。

    Java 5.0+ 以字节码记录通用信息,但不在对象实例中记录。

    例如没有办法得到这个 List 的泛型类型

     // list.getClass() is just ArrayList which doesn't record the generic type.
    List list = new ArrayList<String>();
    

    不过如此

    // list.getClass() is not ArrayList
    // list is an instance of a class which extends ArrayList<String>
    List list = new ArrayList<String>() { };
    
    ParameterizedType t = (ParameterizedType) list.getClass().getGenericSuperclass();
    assert t.getRawType() == ArrayList.class;
    assert t.getActualTypeArguments()[0] == String.class;
    

    这是因为 ArrayList 的子类的字节码记录了其父类中使用的泛型。

    注意:这也适用于作为返回类型的字段、构造函数/方法参数,并且实际类型记录在字节码中。

    但是,这些都不意味着实例的泛型类型可用(尽管如果以字节码记录,父类/接口的泛型类型可能可用。

    【讨论】:

    • 谢谢。无法理解是否只有编译器可以看到这些数据(“编译器需要能够检查泛型类型”),或者在运行时(“ArrayList 的子类的字节码记录了它的父类中使用的泛型”) )
    • @rails 如果可用,您可以使用反射来获取通用信息,但它存在的原因是编译器可以完成它的工作。无法通过这种方式获得仅在运行时才知道的泛型类型。
    • 有一些工具可以帮助编写代码文档(例如 swagger)。由于类型擦除,他们无法记录泛型参数。令我惊讶的是该类包含这些数据
    猜你喜欢
    • 1970-01-01
    • 2023-03-29
    • 2022-07-29
    相关资源
    最近更新 更多