在无界通配符引用对象上使用Object作为参数

时间:2014-07-09 13:08:39

标签: java generics unbounded-wildcard

简单的课程:

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或它的子类。为什么会出现错误呢?

谢谢

2 个答案:

答案 0 :(得分:3)

你的例子清楚地解释了原因。

该框的实际类型为Box<String>。所以你真的不希望能够将除String实例以外的东西放到这个盒子里。

Box<?>表示:“编译器未知的某种类型的框”。所以你可以从这样的盒子中获得你想要的任何东西,你将获得Object实例,但是你可能不会在盒子中存储任何东西,因为编译器不能保证你存储的对象具有合适的类型: / p>

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

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

答案 1 :(得分:1)

This tutorial声明:

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()来返回类型,但你不能添加因为编译器不知道它是什么类型而传递的参数需要扩展未知类型。