使用通用通配符代替接口

Mar*_*tin 12 java generics interface wildcard

如果你想存储一个类型的对象数组,MyInterface以下两者都是可以接受的,如果是这样的话你何时会使用第二个形式而不是第一个?

i)仅使用接口: -

List<MyInterface> mylist = new ArrayList<MyInterface>();
Run Code Online (Sandbox Code Playgroud)

ii)使用通用通配符: -

List<? extends MyInterface> mylist = new ArrayList<? extends MyInterface>();
Run Code Online (Sandbox Code Playgroud)

编辑:

至于到目前为止的答案已经指出,第二号将无法编译.我和案例iii有什么区别:

iii)仅在参考文献中使用通用通配符: -

List<? extends MyInterface> mylist = new ArrayList<MyInterface>();
Run Code Online (Sandbox Code Playgroud)

Vla*_*hev 7

第二个不会编译.想像:

A implements MyInterface
B implements MyInterface
Run Code Online (Sandbox Code Playgroud)

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

// incorrect
List<A> mylist = new ArrayList<B>();
Run Code Online (Sandbox Code Playgroud)

更正:错误的一个:

List<? extends MyInterface> mylist = new ArrayList<MyInterface>();
Run Code Online (Sandbox Code Playgroud)

从某种意义上来说它确实是编译的,但你不能在其中添加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>();
Run Code Online (Sandbox Code Playgroud)

所以这不起作用:

mylist.add(b);
Run Code Online (Sandbox Code Playgroud)

反之亦然.编译器拒绝执行那些可能不正确的操作.

允许您将MyInterface的任何子类添加到mylist的选项是:

List<MyInterface> mylist = new ArrayList<MyInterface>();
Run Code Online (Sandbox Code Playgroud)


Pre*_*raj 5

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

List<MyInterface> mylist = new ArrayList<MyInterface>();
Run Code Online (Sandbox Code Playgroud)

但是,如果要在method参数中使用,则可以使用选项2(有界通配符类型)来提高API的灵活性。

public void someMethod(List<? extends MyInterface> myInterfaces);
Run Code Online (Sandbox Code Playgroud)

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

public class A implements MyInterface {
  // some implementation 
}
Run Code Online (Sandbox Code Playgroud)

并且如果someMethod具有参数类型List<MyInterface>,则将无法使用List<A>,这将迫使API用户在另一侧List使用类型创建MyInterface-
List<? extends MyInterface>允许传递List<A>someMethod..客户端通常具有,List<ActualObject>因此提供参数更灵活将采用任何实现,MyInterface

同时不要将通配符类型用作返回类型,例如

public List<? extends MyInterface> someMethod();
Run Code Online (Sandbox Code Playgroud)

如果类的用户必须考虑通配符类型,则类的API可能存在问题。


Paŭ*_*ann 5

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

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

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