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

时间:2014-03-17 23:15:20

标签: java generics

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

class Gen<T> { }

class Gen2<T> extends Gen<T> { }

现在,书中指出以下内容不会编译(让我们假设它在主方法中)

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

if (obj instanceof Gen2<Integer>) {

    //do something
}

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

if (obj instanceof Gen<?>) {

    //do something else

}

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

3 个答案:

答案 0 :(得分:7)

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

我说几乎所有这些信息,因为在some special cases它仍然在运行时。

答案 1 :(得分:6)

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

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

  

在类型擦除过程中,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; }
    // ...
}

在类型擦除后成为这个:

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; }
    // ...
}

如果你踏上reflection的路径,就像光剑那样,有一种方法可以复活某些类型的信息:强大但又危险。

答案 2 :(得分:0)

泛型被引入到Java语言中,以便在编译时提供更严格的类型检查,并支持泛型编程。 [...]类型擦除确保不为参数化类型创建新类;因此,泛型不会产生运行时开销。

我认为这根本不与向后兼容性有关。如果您编译的代码目标为1.5或更多,则代码将与1.4不兼容,无论使用泛型。