<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和supertypes常常是子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(不是!!!)。