3

简单类:

class Box<T> {
    private T t;

    public Box(T t) {
        this.t = t;
    }

    public void put(T t) {
        this.t = t;
    }
}

尝试执行传递 Object 实例的 put() 方法

Box<?> box = new Box<String>("abc");
box.put(new Object());

编译器指出一个错误:

The method put(capture#1-of ?) in the type Box<capture#1-of ?> is not applicable for the arguments (Object)

编译器实际上不知道期望什么类型,但有一件事是肯定的——它将是一个 Object 或它的子类。为什么会引发错误呢?

谢谢你

4

2 回答 2

5

您的示例清楚地解释了原因。

盒子的实际类型是Box<String>。所以你真的不想把 String 实例以外的东西放到这个盒子里。

Box<?>意思是:“编译器不知道的某种类型的盒子”。所以你可以从这样一个盒子里得到你想要的任何东西,你会得到 Object 实例,但你不能在盒子里存储任何东西,因为编译器不能保证你存储的对象具有适当的类型:

class Box<T> {
    private T t;

    public Box(T t) {
        this.t = t;
    }

    public void put(T t) {
        this.t = t;
    }

    public T get() {
        return t;
    }
}

Box<?> box = new Box<String>("abc");
Object o = box.get(); // no problem
box.put(new Object()); // fail

泛型的目标是使您的代码类型安全。如果您可以将任意对象添加到实际上是 a 的框Box<String>,那么您将不再具有任何类型安全性。

于 2014-07-09T14:09:31.587 回答
1

本教程指出:

Collection<?> c = new ArrayList<String>();
c.add(new Object()); // Same compile time error as yours

“因为我们不知道 c 的元素类型代表什么,所以我们不能向它添加对象。add() 方法接受类型为 E 的参数,即集合的元素类型。当实际类型参数为 ? 时,它代表一些未知类型。我们传递给 add 的任何参数都必须是这个未知类型的子类型。由于我们不知道那是什么类型,所以我们不能传递任何东西。唯一的例外是 null,它是一个成员每种类型。

另一方面,给定一个 List,我们可以调用 get() 并使用结果。结果类型是未知类型,但我们始终知道它是一个对象。因此,将 get() 的结果分配给 Object 类型的变量或将其作为参数传递给期望为 Object 类型的变量是安全的。”

解释一下,基本上可以调用get()返回类型,但是不能添加,因为编译器不知道是什么类型,传入的参数需要扩展未知类型。

于 2014-07-09T14:34:05.427 回答