考虑一下官方帮助中的例子:
public class Node<T>{
private T data;
public Node(T data){ this.data=data; }
public void setData(T data){
System.out.println("Node.setData");
this.data=data;
}
}
public class MyNode extends Node<Integer>{
public MyNode (Integer data){ super(data); }
public void setData (Integer data){
System.out.println("MyNode.setData");
this.data=data;
}
}
public class MyClass{
public static void main(String[] args){
Node n = new MyNode(5);
n.setData(new Object());//ok
}
}
什么意思是Node n= new MyNode(5);
? Node n
是对原始类型的引用,但我将Node<T>
描述为泛型类。原始类型Node
是否为所有Node<T>
的泛型类型T
的超类型?是否真的如果我们定义对原始类型Node n
的引用,其中Node<T>
是泛型类型编译器没有键入选中,但是在Node<T>
中启动了类型擦除?编译器默认情况下将T
与Object
匹配的声明是错误的,因为Node<Object>
不是Node<Integer>
的超类型。
编译器T
中的类型参数Node<T>
是什么?编译器考虑T
作为参考类型是否属实,但他不知道T
的描述?
答案 0 :(得分:2)
1)
Node n= new MyNode(5);
您有一个指向MyNode对象(Node<Integer>
的子类)的原始(未指定类型)节点引用。
原始类型Node是否为所有T的泛型类型节点的超类型?
Node不是Node<T>
如果我们定义对原始类型Node n的引用是真的,其中
Node<T>
是泛型类型编译器没有键入选中,但是在Node<T>
中启动了类型擦除?
编译器仅检查引用,如果引用是raw,则可以添加所需的任何类型。泛型被引入到Java语言中,以便在编译时提供更严格的类型检查并支持泛型编程。泛型是一个仅编译器的问题,在编译类型被擦除(擦除)和泛型不会产生运行时开销。
默认情况下,编译器将T与Object匹配的语句是错误的,因为
Node<Object>
不是Node<Integer>
的超类型。
您尚未为通用类Node指定类型,这相当于Node<Object>
。 Node<Object>
不是Node<Integer>
的超类,也不是Node<A>
和Node<B>
的任意组合。它们在运行时都是同一个类!
2)
类型T是您在使用时指定的内容。在Node类定义中,T只是一个占位符,因此您可以在下一行中使用相同的类型来指定数据类型。可以将Node<T>
中的T视为一个参数,而不是在类中的其他地方使用。 (您可以将T替换为您想要的任何变量,但是除非它是我们使用E的集合,否则使用T是惯例。
考虑以下内容......
public class MyClass extends ArrayList<Integer> {
public static void main(String[] args) {
ArrayList<Integer> a = new MyClass();
a.add(new Integer(5));
ArrayList b = a;
b.add(new String("abc"));
for (Integer i : a) {
//System.out.print(i);
}
}
}
这将编译得很好,因为a是一个ArrayList。
请记住,泛型仅适用于编译器,因此一旦编译它们就不再影响代码了。我们可以使用原始类型的引用b为同一个对象设置别名,从而允许我们将其他对象添加到列表中(例如字符串)。
现在当我们尝试循环遍历整数的ArrayList时,我们惊讶于运行时发现它包含一个String,完全允许添加(因为所有ArrayLists在运行时都是ArrayList<Object>
)但是不允许被强制转换为整数。
Exception in thread "main" java.lang.ClassCastException: java.lang.String cannot be cast to java.lang.Integer
at MyClass.main(MyClass.java:11)