简体   繁体   English

Java中的泛型,使用通配符

[英]Generics in Java, using wildcards

I have a question about Generics in Java, namely using wildcards. 我有一个关于Java中泛型的问题,即使用通配符。 I have an example class GenClass like this: 我有一个像这样的示例类GenClass:

public class GenClass<E> {

    private E var;

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

    public E getVar() {
        return var;
    }
}

I have another simple class: 我有另一个简单的类:

public class ExampleClass {

}

I have written the following test class: 我写了以下测试类:

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
    }

}

Now, if I use a wildcard and write in the test class this: 现在,如果我使用通配符并在测试类中写入:

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

on the place of: 在以下的地方:

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

the compiler has no problem with this new statement, however, it complains about 编译器对这个新语句没有任何问题,但它抱怨

c.setVar(ec);

It says that "the method (setVar()) is not applicable for the arguments (ExampleClass)". 它说“方法(setVar())不适用于参数(ExampleClass)”。 Why do I get this message? 为什么我收到此消息?

I thought that the way I have used the wildcard, makes the reference variable c be of type GenClass, which would accept as parameter any class - on the place of EI would have any class. 我认为我使用通配符的方式使得引用变量c的类型为GenClass,它将接受任何类作为参数 - 在EI的位置上将具有任何类。 This is just the declaration of the variable. 这只是变量的声明。 Then I initialize it with 然后我用它初始化它

new GenClass<ExampleClass>()

which means that I create an object of type GenClass, which has as parameter a class of type ExampleClass. 这意味着我创建了一个GenClass类型的对象,它具有一个类型为ExampleClass的参数。 So, I think that now E in GenClass will be ExampleClass, and I would be able to use the method setVar(), giving it as argument something of type ExampleClass. 所以,我认为现在GenClass中的E将是ExampleClass,我将能够使用方法setVar(),将其作为类型为ExampleClass的参数。 This was my assumption and understanding, but it seems that Java does not like it, and I am not right. 这是我的假设和理解,但似乎Java不喜欢它,我不对。 Any comment is appreciated, thank you. 任何评论表示赞赏,谢谢。

This exact situation is covered in the Java Generics Tutorial . Java Generics Tutorial中介绍了这种确切的情况。

Notice that [with the wildcard], we can still read elements from [the generic Collection ] and give them type Object . 请注意,[使用通配符],我们仍然可以从[泛型Collection ]中读取元素并为它们指定类型Object This is always safe, since whatever the actual type of the collection, it does contain objects. 这总是安全的,因为无论集合的实际类型如何,它都包含对象。 It isn't safe to add arbitrary objects to it however: 然而,向它添加任意对象是不安全的:

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

Since we don't know what the element type of c stands for, we cannot add objects to it. 由于我们不知道c的元素类型代表什么,我们无法向其添加对象。 The add() method takes arguments of type E , the element type of the collection. add()方法接受类型为E参数,即集合的元素类型。 When the actual type parameter is ? 当实际的类型参数是? , it stands for some unknown type. ,它代表一些未知的类型。 Any parameter we pass to add would have to be a subtype of this unknown type. 我们传递给add任何参数都必须是这种未知类型的子类型。 Since we don't know what type that is, we cannot pass anything in. The sole exception is null , which is a member of every type. 因为我们不知道它是什么类型,所以我们无法传递任何内容。唯一的例外是null ,它是每种类型的成员。

(emphasis mine) (强调我的)

mmyers has the correct answer, but I just wanted to comment on this part of your question (which sounds like your rationale for wanting to use the wildcard): mmyers有正确的答案,但我只想评论你的问题的这一部分(这听起来像你想要使用通配符的理由):

I thought that the way I have used the wildcard, makes the reference variable c be of type GenClass, which would accept as parameter any class - on the place of EI would have any class. 我认为我使用通配符的方式使得引用变量c的类型为GenClass,它将接受任何类作为参数 - 在EI的位置上将具有任何类。 This is just the declaration of the variable. 这只是变量的声明。 Then I initialize it with 然后我用它初始化它

If you really want to accomplish this, you could do something like without compilation errors: 如果你真的想要完成这个,你可以做一些没有编译错误的事情:

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

But then again, if you want to declare an instance of GenClass that can contain any type, I'm not sure why you'd want to use generics at all - you could just use the raw class: 但话又说回来,如果你想声明一个可以包含任何类型的GenClass实例,我不确定你为什么要使用泛型 - 你可以只使用原始类:

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM