【发布时间】:2014-10-11 06:31:43
【问题描述】:
具有List<interfaceI> 和List<? extends InterfaceI> 的Arraylist 都将具有实现接口I 的类的对象。那什么时候用呢?
【问题讨论】:
-
这取决于你想如何使用你的
List。
标签: java generics collections arraylist
具有List<interfaceI> 和List<? extends InterfaceI> 的Arraylist 都将具有实现接口I 的类的对象。那什么时候用呢?
【问题讨论】:
List。
标签: java generics collections arraylist
假设Foo 和Bar 是实现InterfaceI 的两个类。
第二个 (List<? extends InterfaceI>) 不允许向列表添加任何内容(null 除外),因为列表包含的类型未知:它可能是 List<Foo> 或 List<Bar>:你只是不知道。
因此,当您希望该方法读取作为参数传递的列表的元素,并希望调用者能够使用List<InterfaceI>、List<Foo> 或 List<Bar>。使用List<InterfaceI> 作为参数只会接受List<InterfaceI> 类型的列表。
让我们举一个具体的例子:你想计算一个数字列表的最大双精度值。这种方法不需要向列表添加或设置任何内容。它所做的只是迭代元素,获取每个数字并计算它们的最大值。签名可以是
public double max(List<Number> list);
但是,你将无法做到
List<Integer> ints = new ArrayList<>();
max(ints);
调用这个方法的唯一方法是做
List<Number> ints = new ArrayList<>();
max(ints);
如果你将方法声明为
public double max(List<? extends Number> list);
那你就可以了
List<Integer> ints = new ArrayList<>();
List<Long> longs = new ArrayList<>();
max(ints);
max(longs)
【讨论】:
不同之处在于,如果您将列表声明为List<? extends S> myList,则myList 变量可以通过扩展S 的任何类型的列表,因此如下所示的关联将起作用:
public class Clazz implements S{}
List<? extends S> myList = new List<Clazz>(); // its fine as Clazz extends S
List<? extends S> myList = new List<S>(); // its fine as well
List<? extends S> myList = new List<Object>(); // ooooops it wil not work
但是在这种情况下,您将不会对 PUT 这样的列表进行任何操作,因为您无法保证分配给 myList 的列表实现所持有的对象的确切类型
如果您声明List<S> myList,那么您将能够从列表中获得PUT 和GET 对象,因为您确定其中有什么,但是上面的分配将不起作用!
public class Clazz implements S{}
List<S> myList = new List<Clazz>(); // no way!
List<S> myList = new List<S>(); //thats perfectly fine! - You can PUT new S in it;
List<S> myList = new List<Object>(); //known result;
【讨论】:
这里代替这个
public double max(List<? extends Number> list){
如果你喜欢-
public List myList(List<? extends String> list){
list.add("string");// No, can not add anything in list except null
list.add(null);
}
【讨论】: