之前可能已经提出这个问题,但我一直无法找到问题。
我想了解以下代码块无法编译的根本原因:
public class Box<T> {
private T value;
public Box(T value) {
this.value = value;
}
public T getValue() {
return value;
}
public static void main(String[] args) {
Box<Integer> i = new Box<Integer>(13);
// does not compile
Box<Object> o = i;
}
}
答案 0 :(得分:2)
首先,您无法转换参数化类型。请检查此oracle doc。
通常,您不能转换为参数化类型,除非它是 由无界通配符参数化。例如:
列表li = new ArrayList&lt;&gt;();
List ln =(List)li; //编译时错误
因此,行Box<Object> o = i;
会导致编译时错误。
即使在创建Box
对象时,您还没有指定泛型参数,而是使用构造函数参数类型 java Type inference构造对象的类型。
答案 1 :(得分:2)
查看它的一种方法是,我们假设Box
定义了void setValue(T val)
方法。
Box<Object> o = i;
o.setValue("a string");
Integer x = i.getValue(); // ?!
答案 2 :(得分:2)
这里的java文档中提到了这个问题(类似于Vlad的回答):
https://docs.oracle.com/javase/tutorial/extra/generics/subtype.html
让我们测试一下你对泛型的理解。以下代码段是否合法?
List<String> ls = new ArrayList<String>(); // 1 List<Object> lo = ls; // 2
第1行肯定是合法的。问题的棘手部分是第2行。这归结为一个问题:是一个String列表对象列表。大多数人本能地回答:“当然!”
好吧,看看接下来几行:
lo.add(new Object()); // 3 String s = ls.get(0); // 4: Attempts to assign an Object to a String!
这里我们别名ls和lo。通过别名lo访问ls,一个String列表,我们可以在其中插入任意对象。因此,ls不再仅仅支持Strings,当我们尝试从中获取某些东西时,我们会得到一个粗鲁的惊喜。
答案 3 :(得分:1)
您可以为Object
引用分配任何引用,但是当泛型启动时,在编译时匹配确切的泛型类型。因此它不起作用。如果您更改为Box<? extends Object> o = i;
它将起作用,因为泛型类型与包含的类型匹配。