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

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

class Gen { } class Gen2 extends Gen { } 

现在这本书说明以下将不会编译(让我们假设它在一个主方法中)

 Gen2 obj = new Gen2(); if (obj instanceof Gen2) { //do something } 

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

 if (obj instanceof Gen) { //do something else } 

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

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

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

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

所以这个代码就是例子

 public class Node> { private T data; private Node next; public Node(T data, Node 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路径,有一种方法可以复活一些类型的信息:强大而又危险。

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

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

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

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