4

我有一个关于 Java 中的泛型的问题,即使用通配符。我有一个像这样的示例类 GenClass:

public class GenClass<E> {

    private E var;

    public void setVar(E x) {
        var = x;
    }

    public E getVar() {
        return var;
    }
}

我有另一个简单的类:

public class ExampleClass {

}

我编写了以下测试类:

public class TestGenClass {

    public static void main(String[] str) {

        ExampleClass ec = new ExampleClass();

        GenClass<ExampleClass> c = new GenClass<ExampleClass>();

        c.setVar(ec);
        System.out.println(c.getVar());  // OUTPUT: ExampleClass@addbf1
    }

}

现在,如果我使用通配符并在测试类中这样写:

GenClass<?> c = new GenClass<ExampleClass>();

在:

GenClass<ExampleClass> c = new GenClass<ExampleClass>();

编译器对这个新语句没有问题,但是,它抱怨

c.setVar(ec);

它说“方法(setVar())不适用于参数(ExampleClass)”。为什么我会收到此消息?

我认为我使用通配符的方式使引用变量 c 的类型为 GenClass,它可以接受任何类作为参数 - 在 EI 的位置上会有任何类。这只是变量的声明。然后我用它初始化它

new GenClass<ExampleClass>()

这意味着我创建了一个 GenClass 类型的对象,它有一个 ExampleClass 类型的类作为参数。所以,我认为现在 GenClass 中的 E 将是 ExampleClass,并且我将能够使用方法 setVar(),将其作为参数类型为 ExampleClass。这是我的假设和理解,但Java似乎不喜欢它,我也不对。任何评论表示赞赏,谢谢。

4

2 回答 2

14

Java 泛型教程中涵盖了这种确切情况。

请注意,[使用通配符],我们仍然可以从 [通用Collection] 中读取元素并赋予它们 type Object。这总是安全的,因为无论集合的实际类型是什么,它都包含对象。但是,向其中添加任意对象是不安全的:

Collection<?> c = new ArrayList<String>();
c.add(new Object()); // Compile time error

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

(强调我的)

于 2009-02-02T16:12:47.730 回答
2

mmyers 有正确的答案,但我只是想评论您问题的这一部分(这听起来像是您想要使用通配符的理由):

我认为我使用通配符的方式使引用变量 c 的类型为 GenClass,它可以接受任何类作为参数 - 在 EI 的位置上会有任何类。这只是变量的声明。然后我用它初始化它

如果你真的想做到这一点,你可以做一些没有编译错误的事情:

GenClass<Object> gc = new GenClass<Object>();
gc.setVar(new ExampleClass());

但是话又说回来,如果你想声明一个GenClass可以包含任何类型的实例,我不确定你为什么要使用泛型——你可以只使用原始类:

GenClass raw = new GenClass();
raw.setVar(new ExampleClass());
raw.setVar("this runs ok");
于 2009-02-02T16:30:51.687 回答