<E extends Number>和<Number>之间有什么区别?
这个方法声明有什么区别:
public static <E extends Number> List<E> process(List<E> nums){
和
public static List<Number> process(List<Number> nums){
你会在哪里使用前者?
第一个允许List<Integer>
, List<Double>
等的过程。第二个不允许。
Java中的generics是不变的。 它们不像数组一样协变。
也就是说,在Java中, Double[]
是Number[]
的子types,但List<Double>
不是List<Number>
的子types。 List<Double>
是List<? extends Number>
List<? extends Number>
。
generics是不变的,这也是很好的原因,但这也是为什么extends
和super
types常常是子types灵活性所必需的。
也可以看看
- Java教程/generics/子types
- 解释为什么generics不变是一件好事
- 通配符更有趣
- 解释了
super
一些用法,并extends
了有界的通配符
- 解释了
- Javagenerics:什么是PECS?
- 这里讨论“生产者
extends
消费者super
”的原则 - Effective Java第2版 ,第28项:使用有界通配符来增加API的灵活性
- 这里讨论“生产者
后一种方法 ( 没有 <E extends Number>
)只接受一个List<Number>
types的参数,并且总是返回一个List<Number>
。 例如,它不会接受List<Integer>
。
前一种方法 ( 带有 <E extends Number>
方法 )是一个通用的方法 ,这意味着它可以接受不同types的List
,并且它将返回相同types的List
,只要List
是一些扩展Number
,例如List<Integer>
。
例:
import java.util.ArrayList; import java.util.List; public class ProcessGenerics { List<Number> listNumber = new ArrayList<Number>(); List<Integer> listInteger = new ArrayList<Integer>(); List<Double> listDouble = new ArrayList<Double>(); public static List<Number> processWithoutExtends(List<Number> nums){ return nums; } List<Number> resultN = processWithoutExtends(listNumber); // OK //List<Integer> resultI = processWithoutExtends(listInteger); // compile-error - method not applicable //List<Double> resultD = processWithoutExtends(listDouble); // compile-error - method not applicable public static <E extends Number> List<E> processWithExtends(List<E> nums){ return nums; } List<Number> resultN2 = processWithExtends(listNumber); // OK List<Integer> resultI2 = processWithExtends(listInteger); // OK List<Double> resultD2 = processWithExtends(listDouble); // OK }
在Java教程的generics课程的通配符一章中看到类似的解释:
http://java.sun.com/docs/books/tutorial/java/generics/subtyping.html
另请参见如何将inheritance对象的列表转换为Java中的对象集合? 这两个问题都是关于generics和子types,例如List<Integer>
是List<Number>
的子types(不是!!!)。