在Java中,为什么运行时没有泛型类型信息?

Rob*_*b L 5 java generics

考虑这个例子来自一本书,有一个超类Gen和一个子类Gen2 ...

class Gen<T> { }

class Gen2<T> extends Gen<T> { }
Run Code Online (Sandbox Code Playgroud)

现在这本书的状态将不会编译(让我们假设它在一个主方法中)

Gen2<Integer> obj = new Gen2<Integer>();

if (obj instanceof Gen2<Integer>) {

    //do something
}
Run Code Online (Sandbox Code Playgroud)

无法编译,因为运行时不存在泛型类型信息.如果它在运行时不存在,它何时存在?我认为它在编译时不会存在,但会在运行时存在.当然,以下适用于带有通配符的运行时...

if (obj instanceof Gen<?>) {

    //do something else

}
Run Code Online (Sandbox Code Playgroud)

所以要澄清一下,我的问题是为什么通用类型信息在运行时不存在?我忽略了一个简单的概念吗?

Ada*_*old 8

问题是java中并不总是存在泛型(我认为它们在1.5中添加了它).因此,为了能够实现向后兼容性,存在类型擦除,其在编译代码时有效地擦除泛型类型信息以实现该目标.

摘自官方文件的相关部分:

在类型擦除过程中,Java编译器将擦除所有类型参数,并在类型参数有界时将其替换为第一个绑定,如果类型参数为无界,则替换为Object.

所以这段代码就是例子

public class Node<T extends Comparable<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; }
    // ...
}
Run Code Online (Sandbox Code Playgroud)

在类型擦除后成为这个:

public class Node {

    private Comparable data;
    private Node next;

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

    public Comparable getData() { return data; }
    // ...
}
Run Code Online (Sandbox Code Playgroud)

然而,如果你走的是像光剑一样的反射路径,有一种方法可以复活一些类型的信息:强大而又危险.


Jud*_*tal 7

你"忽略了一个简单的概念".泛型在编译时存在,并且仅用于执行诸如参数多态之类的事情.因为实现它们的人决定开发人员应该能够使用它们(泛型)并且仍然将他们构建的工件部署到具有旧JVM的目标(在我看来这是一个非常可疑的决定,因为运行时库也在1.4和1.5之间变化),他们让编译器决定是否所有类型检查,然后在创建编译工件之前丢弃几乎所有信息.

我说几乎所有这些信息,因为在某些特殊情况下它仍然在运行时.

  • +1称其为"一个极其可疑的决定".:) (6认同)