Java中的泛型,使用通配符

时间:2009-02-02 16:01:33

标签: java generics bounded-wildcard

我对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,它将接受任何类的参数 - 在E的位置我会有任何类。这只是变量的声明。然后我用

初始化它
new GenClass<ExampleClass>()

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

2 个答案:

答案 0 :(得分:14)

Java Generics Tutorial

涵盖了这种确切情况
  

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

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

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

(强调我的)

答案 1 :(得分:2)

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

  

我认为我使用通配符的方式使得引用变量c的类型为GenClass,它将接受任何类的参数 - 在E的位置我会有任何类。这只是变量的声明。然后我用

初始化它

如果你真的想要完成这个,你可以做一些没有编译错误的事情:

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

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

GenClass raw = new GenClass();
raw.setVar(new ExampleClass());
raw.setVar("this runs ok");