如果你想存储MyInterface
类型的对象数组,以下两者都是可接受的,如果是这样的话你何时会使用第二种形式而不是第一种?
i)仅使用界面: -
List<MyInterface> mylist = new ArrayList<MyInterface>();
ii)使用通用通配符: -
List<? extends MyInterface> mylist = new ArrayList<? extends MyInterface>();
编辑:
到目前为止的答案已经指出,第二号将无法编译。 i和案例iii之间有什么区别: -
iii)仅在参考中使用通用通配符: -
List<? extends MyInterface> mylist = new ArrayList<MyInterface>();
答案 0 :(得分:7)
第二个不会编译。想象:
A implements MyInterface
B implements MyInterface
然后以下内容将匹配您的第二个表达式,但不会编译:
// incorrect
List<A> mylist = new ArrayList<B>();
更正:错误:
List<? extends MyInterface> mylist = new ArrayList<MyInterface>();
在某种意义上它确实是编译的,但是你不能向它添加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>();
所以这不起作用:
mylist.add(b);
反之亦然。编译器拒绝执行那些可能不正确的操作。
允许您将MyInterface的任何子类添加到mylist的选项是:
List<MyInterface> mylist = new ArrayList<MyInterface>();
答案 1 :(得分:4)
如果您想存储MyInterface
类型的对象,那么更好(和可编辑)的方法将是 -
List<MyInterface> mylist = new ArrayList<MyInterface>();
但是如果您想在方法参数中使用,那么您可以使用选项2(有界通配符类型)来实现API灵活性。
public void someMethod(List<? extends MyInterface> myInterfaces);
修改强>
上面的代码将提供更灵活的API,因为Generic类型是不变的,所以如果你有 -
public class A implements MyInterface {
// some implementation
}
如果someMethod
的参数类型为List<MyInterface>
,那么它将无法使用List<A>
,这会强制API用户使用{{1}类型创建List
1}}另一方面 - MyInterface
允许将List<? extends MyInterface>
传递给List<A>
..客户通常会有一个someMethod
,因此提供一个List<ActualObject>
更灵活参数将采用MyInterface
的任何实现
同时不使用通配符类型作为返回类型,如
public List<? extends MyInterface> someMethod();
如果一个类的用户必须考虑通配符类型,那么该类的API可能有问题。
答案 2 :(得分:4)
List<? extends MyInterface>
表示某个MyInterface
子类型的列表,但我们不知道哪个子类型。
由于我们不知道实际使用了哪个子类型,因此我们不能在其中放置任何对象(因为我们无法确保它是此子类型的元素)。
我们可以从这样的列表中取出对象,并且知道它是一个实现MyInterface
的对象,但仅此而已。
答案 3 :(得分:2)
不同之处在于第二个不会编译。您不能使用带边界的其他类型参数来实例化类型参数。
答案 4 :(得分:0)
在实现中使用完全和完整的类型信息。
ArrayList<MyInterface> mylist = new ArrayList<MyInterface>();