使用泛型通配符而不是接口

时间:2022-09-01 23:17:22

If you wanted to store an array of objects of type MyInterface, are the following both acceptable and if so when would you use the second form over the first?

如果您想要存储MyInterface类型的对象数组,是否可以接受以下内容,如果可以,什么时候在第一个表单中使用第二个表单?

i) Using only an interface:-

i)只使用一个接口:-

List<MyInterface> mylist = new ArrayList<MyInterface>();

ii) Using a generic wildcard:-

使用通用通配符:-

List<? extends MyInterface> mylist = new ArrayList<? extends MyInterface>();

Edit:

编辑:

As the answers so far have pointed out, number ii won't compile. What is the difference between i and a case iii where :-

正如目前为止的答案所指出的那样,第二种方法不会被编译。我和案例三的区别在哪里:- ?

iii) Using a generic wildcard only in the reference:-

iii)仅在引用中使用泛型通配符:-

List<? extends MyInterface> mylist = new ArrayList<MyInterface>();

5 个解决方案

#1


7  

Second one won't compile. Imagine:

第二个不会编译。想象一下:

A implements MyInterface
B implements MyInterface

Then the following would match your second expression, but won't compile:

然后下面的语句将匹配您的第二个表达式,但不会编译:

// incorrect
List<A> mylist = new ArrayList<B>();

Correction: Wrong one too:

更正:错误的:

List<? extends MyInterface> mylist = new ArrayList<MyInterface>();

It is right in a sense it does compile, but you cannot add any subclasses of MyInterface to it. Confusing, but correct -- after I read the explanation. Same reason: wildcard can be viewed for example as:

从某种意义上说,它确实可以编译,但是不能向它添加任何MyInterface的子类。困惑,但正确——在我读了解释之后。同样的原因:可以查看通配符,例如:

// I know this is not compileable; this is internal compiler "thinking".
// Read it as "somewhere someone may instantiate an ArrayList<A> and pass 
// it down to us; but we cannot accept it as something that could be 
// potentially used as List<B>"
List<A> mylist = new ArrayList<MyInterface>();

So this won't work:

这是行不通的:

mylist.add(b);

and vice versa. Compiler refuses to do those potentially incorrect operations.

反之亦然。编译器拒绝执行那些潜在的错误操作。

The option which allows you to add any subclass of MyInterface to mylist is:

可以添加MyInterface myto mylist任何子类的选项是:

List<MyInterface> mylist = new ArrayList<MyInterface>();

#2


4  

If you would like to store the ojects of type MyInterface the better (and compilable) approach would be -

如果您想存储MyInterface类型的对象,更好的(和可编译的)方法是-

List<MyInterface> mylist = new ArrayList<MyInterface>();

But if you would like to use in the method parameter then you can use option 2 (bounded wildcard type) for API flexibility.

但是如果您想在方法参数中使用,那么您可以使用选项2(有界通配符类型)来实现API的灵活性。

public void someMethod(List<? extends MyInterface> myInterfaces);

EDIT:
The above code will give the more flexibility API because Generic types are invariant, so if you have -

编辑:上面的代码将提供更灵活的API,因为泛型类型是不变的,所以如果您有-

public class A implements MyInterface {
  // some implementation 
}

and if someMethod has a parameter type List<MyInterface> then it won't be able to take the List<A>, this forces API users to create List with type MyInterface on the other side -
List<? extends MyInterface> will allow to pass List<A> to someMethod.. client usually has a List<ActualObject> so it's more flexible to provide a parameter which will take any implementation of MyInterface

At the same time do not use wildcard types as return types like

如果someMethod有一个参数类型列表 那么它就不能获取列表< a >,这就迫使API用户创建另一端为MyInterface类型的列表- List 允许将List 传递给someMethod。客户端通常有一个列表 ,所以更灵活的方法是提供一个参数,它将同时接受MyInterface的任何实现,不要像返回类型那样使用通配符类型

public List<? extends MyInterface> someMethod();

If the user of a class has to think about wildcard types, there is probably something wrong with the class’s API.

如果一个类的用户必须考虑通配符类型,那么这个类的API可能有问题。

#3


4  

List<? extends MyInterface> means a list of some subtype of MyInterface, but we don't know which subtype.

列表< ?扩展MyInterface>表示MyInterface的某个子类型的列表,但是我们不知道是哪个子类型。

Since we don't know which subtype is used actually, we can't put any object in it (as we can't ensure that it is an element of this subtype).

因为我们不知道实际使用的是哪个子类型,所以我们不能在其中放入任何对象(因为我们不能确保它是该子类型的元素)。

We can take objects out of such a list, and know that it is an object implementing MyInterface, but nothing more.

我们可以从这样的列表中取出对象,并知道它是一个实现MyInterface的对象,仅此而已。

#4


2  

The difference is that the second will not compile. You can't instantiate a type parameter with another type parameter with bounds.

不同的是,第二个不会编译。不能用另一个带边界的类型参数实例化一个类型参数。

#5


0  

use exact and complete type info in implementations.

在实现中使用准确和完整的类型信息。

ArrayList<MyInterface> mylist = new ArrayList<MyInterface>();

#1


7  

Second one won't compile. Imagine:

第二个不会编译。想象一下:

A implements MyInterface
B implements MyInterface

Then the following would match your second expression, but won't compile:

然后下面的语句将匹配您的第二个表达式,但不会编译:

// incorrect
List<A> mylist = new ArrayList<B>();

Correction: Wrong one too:

更正:错误的:

List<? extends MyInterface> mylist = new ArrayList<MyInterface>();

It is right in a sense it does compile, but you cannot add any subclasses of MyInterface to it. Confusing, but correct -- after I read the explanation. Same reason: wildcard can be viewed for example as:

从某种意义上说,它确实可以编译,但是不能向它添加任何MyInterface的子类。困惑,但正确——在我读了解释之后。同样的原因:可以查看通配符,例如:

// I know this is not compileable; this is internal compiler "thinking".
// Read it as "somewhere someone may instantiate an ArrayList<A> and pass 
// it down to us; but we cannot accept it as something that could be 
// potentially used as List<B>"
List<A> mylist = new ArrayList<MyInterface>();

So this won't work:

这是行不通的:

mylist.add(b);

and vice versa. Compiler refuses to do those potentially incorrect operations.

反之亦然。编译器拒绝执行那些潜在的错误操作。

The option which allows you to add any subclass of MyInterface to mylist is:

可以添加MyInterface myto mylist任何子类的选项是:

List<MyInterface> mylist = new ArrayList<MyInterface>();

#2


4  

If you would like to store the ojects of type MyInterface the better (and compilable) approach would be -

如果您想存储MyInterface类型的对象,更好的(和可编译的)方法是-

List<MyInterface> mylist = new ArrayList<MyInterface>();

But if you would like to use in the method parameter then you can use option 2 (bounded wildcard type) for API flexibility.

但是如果您想在方法参数中使用,那么您可以使用选项2(有界通配符类型)来实现API的灵活性。

public void someMethod(List<? extends MyInterface> myInterfaces);

EDIT:
The above code will give the more flexibility API because Generic types are invariant, so if you have -

编辑:上面的代码将提供更灵活的API,因为泛型类型是不变的,所以如果您有-

public class A implements MyInterface {
  // some implementation 
}

and if someMethod has a parameter type List<MyInterface> then it won't be able to take the List<A>, this forces API users to create List with type MyInterface on the other side -
List<? extends MyInterface> will allow to pass List<A> to someMethod.. client usually has a List<ActualObject> so it's more flexible to provide a parameter which will take any implementation of MyInterface

At the same time do not use wildcard types as return types like

如果someMethod有一个参数类型列表 那么它就不能获取列表< a >,这就迫使API用户创建另一端为MyInterface类型的列表- List 允许将List 传递给someMethod。客户端通常有一个列表 ,所以更灵活的方法是提供一个参数,它将同时接受MyInterface的任何实现,不要像返回类型那样使用通配符类型

public List<? extends MyInterface> someMethod();

If the user of a class has to think about wildcard types, there is probably something wrong with the class’s API.

如果一个类的用户必须考虑通配符类型,那么这个类的API可能有问题。

#3


4  

List<? extends MyInterface> means a list of some subtype of MyInterface, but we don't know which subtype.

列表< ?扩展MyInterface>表示MyInterface的某个子类型的列表,但是我们不知道是哪个子类型。

Since we don't know which subtype is used actually, we can't put any object in it (as we can't ensure that it is an element of this subtype).

因为我们不知道实际使用的是哪个子类型,所以我们不能在其中放入任何对象(因为我们不能确保它是该子类型的元素)。

We can take objects out of such a list, and know that it is an object implementing MyInterface, but nothing more.

我们可以从这样的列表中取出对象,并知道它是一个实现MyInterface的对象,仅此而已。

#4


2  

The difference is that the second will not compile. You can't instantiate a type parameter with another type parameter with bounds.

不同的是,第二个不会编译。不能用另一个带边界的类型参数实例化一个类型参数。

#5


0  

use exact and complete type info in implementations.

在实现中使用准确和完整的类型信息。

ArrayList<MyInterface> mylist = new ArrayList<MyInterface>();