是与参数化引用的关系

时间:2016-01-22 08:50:05

标签: java generics

之前可能已经提出这个问题,但我一直无法找到问题。

我想了解以下代码块无法编译的根本原因:

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;
    }

}

4 个答案:

答案 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;它将起作用,因为泛型类型与包含的类型匹配。