What is the difference between <E extends Number> and <Number>?
What is the开发者_开发技巧 difference between this method declaration:
public static <E extends Number> List<E> process(List<E> nums){
and
public static List<Number> process(List<Number> nums){
Where would you use the former?
The first allows process
of a List<Integer>
, a List<Double>
, etc. The second doesn't.
Generics in Java are invariant. They're not covariant like arrays.
That is, in Java, Double[]
is a subtype of Number[]
, but a List<Double>
is NOT a subtype of List<Number>
. A List<Double>
, however, is a List<? extends Number>
.
There are good reasons for generics being invariant, but that's also why the extends
and super
type are often necessary for subtyping flexibility.
See also
- Java Tutorials/Generics/Subtyping
- Explains why generics invariance is a good thing
- More fun with wildcards
- Explains some uses of
super
andextends
for bounded wildcards
- Explains some uses of
- Java Generics: What is PECS?
- This discusses the "Producer
extends
Consumersuper
" principle - Effective Java 2nd Edition, Item 28: Use bounded wildcards to increase API flexibility
- This discusses the "Producer
The latter method (the one without <E extends Number>
) will only accept a parameter of exactly type List<Number>
and will it always
return a List<Number>
. For example, it will not accept List<Integer>
.
The former method (the one with <E extends Number>
) is a generic method, meaning it can accept different types of List
s
and it will return the same type of List
, as long as the List
s are lists of something that
extends Number
, e.g. List<Integer>
.
Example:
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
}
See a similar explanation in the Wildcards chapter in the Generics Lesson in the Java Tutorials:
http://java.sun.com/docs/books/tutorial/java/generics/subtyping.html
See also How to cast a list of inheriting objects to a collection of objects in Java? Both questions are really about generics and subtypes, e.g. whether List<Integer>
is a subtype of List<Number>
(it's not!!!).
精彩评论