Java中的泛型,使用通配符

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类型,它将接受任何类作为参数 - 在E的位置上,我可以有任何类。这只是变量的声明。然后我用它来初始化。
new GenClass<ExampleClass>()

这意味着我创建了一个类型为GenClass的对象,参数是ExampleClass类型的类。因此,我认为现在GenClass中的E将是ExampleClass,并且我将能够使用setVar()方法,将其参数设置为ExampleClass类型的东西。 这是我的假设和理解,但似乎Java不喜欢它,我是错误的。 您的任何评论都会受到赞赏,谢谢。

1
根据您的用户历史记录,您从未接受过答案。您认为现在可以开始吗?您甚至可以获得2个声望点和一个免费徽章(第一次)。 :D - Michael Myers
2个回答

14

这种情况在Java泛型教程中有详细描述。

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

Collection<?> c = new ArrayList<String>();
c.add(new Object()); // Compile time error
由于我们不知道变量的元素类型,所以无法向其中添加对象。add()方法需要传入E类型的参数,它表示集合的元素类型。当实际类型参数为?时,它代表某种未知类型。我们传递给add的任何参数都必须是这个未知类型的子类型。由于我们不知道该类型是什么,因此我们无法传递任何内容。唯一的例外是null,它是每种类型的成员。

2
mmyers的答案是正确的,但我想评论一下你问题中的这部分(听起来像你想使用通配符的理由):
如果你真的想要实现这个,你可以做一些类似以下的事情而不会出现编译错误:
GenClass<Object> gc = new GenClass<Object>();
gc.setVar(new ExampleClass());

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

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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接