首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Java泛型类型擦除字节码

Java泛型类型擦除字节码
EN

Stack Overflow用户
提问于 2015-03-31 18:14:17
回答 4查看 3.3K关注 0票数 15

根据泛型擦除上的java文档,

考虑以下泛型类,它表示单个链接列表中的节点:

代码语言:javascript
复制
public class Node<T> {

    private T data;
    private Node<T> next;

    public Node(T data, Node<T> next) }
        this.data = data;
        this.next = next;
    }

    public T getData() { return data; }
    // ...
}

由于类型参数T是无界的,所以Java编译器将其替换为对象

代码语言:javascript
复制
public class Node {

    private Object data;
    private Node next;

    public Node(Object data, Node next) {
        this.data = data;
        this.next = next;
    }

    public Object getData() { return data; }
    // ...
}

但是在用1.7.0_11编译之后,当我用任何反编译器打开它时,我可以看到与源代码相同的代码。

代码语言:javascript
复制
public class Node<T>
{
  private T data;
  private Node<T> next;

  public Node(T paramT, Node<T> paramNode)
  {
    this.data = paramT;
    this.next = paramNode;
  }

  public T getData()
  {
    return this.data;
  }
}

如果在编译时应用Type-Erasure,那么字节码就不能包含上面所示的泛型信息。请澄清我。

注意:我正在使用作为一个反编译器来分析字节码。

EN

回答 4

Stack Overflow用户

发布于 2015-03-31 18:19:41

字节码包含关于代码本身的元信息,例如泛型类型(或变量名称)--这并不意味着JVM可以使用它。

类的分解字节码如下所示(您可以在javap -c Node.class中看到它):

代码语言:javascript
复制
public class Node<T> {
  public Node(T, Node<T>);
    Code:
       0: aload_0
       1: invokespecial #1                  // Method java/lang/Object."<init>":()V
       4: aload_0
       5: aload_1
       6: putfield      #2                  // Field data:Ljava/lang/Object;
       9: aload_0
      10: aload_2
      11: putfield      #3                  // Field next:LNode;
      14: return

  public T getData();
    Code:
       0: aload_0
       1: getfield      #2                  // Field data:Ljava/lang/Object;
       4: areturn
}

您可以看到存在方法和参数泛型类型,但是由于擦除过程,代码本身引用了预期的对象。

票数 9
EN

Stack Overflow用户

发布于 2015-03-31 18:20:32

类是泛型的这一事实被保留下来。例如,在运行时您可以调用

代码语言:javascript
复制
Node.class.getTypeParameters()

下一段代码将返回"T“。

代码语言:javascript
复制
(new Node<Integer>()).getClass().getTypeParameters()[0].getName()

您无法在运行时获得类型参数的值,但是JVM知道它们在那里。

当您构造一个实例时,擦除会起作用。

代码语言:javascript
复制
Node<Integer> node = new Node<Integer>(1, null);
Integer i = node.getData();

化作

代码语言:javascript
复制
Node node = new Node(1, null);
Integer i = (Integer)node.getData();

泛型类总是泛型的。但是实例中不包含泛型类型信息。编译器验证您所做的一切是否与泛型类型一致,然后插入强制转换。

票数 8
EN

Stack Overflow用户

发布于 2015-03-31 18:19:05

泛型类型信息仍然保存在字节码中,特别是保存在类成员的签名信息中。

例如,执行javap -verbose Node.class生成:

代码语言:javascript
复制
 ...
 LocalVariableTypeTable:
      Start  Length  Slot  Name   Signature
          0       5     0  this   Ltest/Node<TT;>;

请参阅本节来自JVM规范。

签名编码用Java编程语言编写的声明,这些声明使用Java虚拟机类型系统之外的类型。它们支持反射和调试,以及只有类文件可用时的编译。 Java编译器必须为声明使用类型变量或参数化类型的任何类、接口、构造函数、方法或字段发出签名。具体来说,Java编译器必须发出:

  • 任何类或接口声明的类签名,它们要么是泛型的,要么具有作为超类或超接口的参数化类型,或者两者兼具。
  • 任何方法或构造函数声明的方法签名,这些方法或构造函数声明要么是泛型的,要么是作为返回类型或形式参数类型的类型变量或参数化类型,或者是抛出子句中的类型变量,或者是其中的任何组合。
票数 5
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/29375575

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档