Java泛型类型擦除:字段上的运行时类型检查

时间:2014-07-02 19:14:07

标签: java

我正在学习关于泛型的Java教程,并以我自己的方式在http://docs.oracle.com/javase/tutorial/java/generics/bridgeMethods.html上玩这个例子。

两个班级:

public class Node<T> {
    private T data;
    public Node(T data) { 
        this.data = data; 
    }
    public void setData(T data) {
        this.data = data;
    }
}

public class MyNode extends Node<Integer> {
    public MyNode(Integer data) { 
        super(data); 
    }
    public void setData(Integer data) {
        super.setData(data);
    }
}

由于类型擦除,下面的代码将编译:

MyNode mn = new MyNode(5);  // 1
Node n = mn;                // 2
n.setData("Hello");         // 3

因为第3行实际上是调用类型擦除方法Node.setData(Object)。但是会抛出运行时ClassCastException

以下是我的实验:我打印出字段data的类型。 Node和MyNode中都是Object

以下是我的问题:

  1. 节点具有Object类型,由于类型擦除而没有任何意外。但是,为什么MyNode还有Object类型的数据&#34;数据&#34;?

  2. 如果MyNode&#34;数据&#34;具有Object类型,运行时类型检查如何工作? (ClassCastException异常......)在我看来,MyNode中的数据类型也已被删除(我的拼图#1)。

  3. Java版:HotSpot 1.8.0_05-b13

2 个答案:

答案 0 :(得分:2)

这与GenericsType Erasure无关。

您告诉编译器Node n并且没有提供任何类型,因此它将需要任何内容​​。

这与将ArrayList<String>向下转换为List并抱怨任何抱怨并没有什么不同。

final List los = new ArrayList<String>();
los.add(new Date());
los.add(1);

这是明确定义和预期的行为,它正在做你要告诉它的事情。

除了你要告诉它做什么之外,你还期望它做什么?

答案 1 :(得分:2)

  

我打印出了字段数据的类型

你打印出来的是一种名为“data”的refence类型。确实设置为Object

  

但是为什么MyNode也有“数据”的对象类型?

不确定您正在谈论哪些数据。局部变量data的引用类型将为Integer,而属性引用类型为Object

  

如果MyNode的“数据”具有Object类型,运行时类型检查如何工作? (ClassCastException异常......)在我看来,MyNode中的数据类型也被删除了(我的拼图#1)。

执行此操作时:

public void setData(Integer data) {
        super.setData(data);
}

Java编译器只需将其转换为:

public void setData(Object arg) {
   Integer data = (Integer) arg;
    //Now you can use "data" refenrence with proper type
   super.setData(data);
}

这是ClassCastException的来源。