考虑这个例子来自一本书,有一个超类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
}
所以要澄清一下,我的问题是为什么通用类型信息在运行时不存在?我忽略了一个简单的概念吗?
答案 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不兼容,无论使用泛型。