开发者

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 and extends for bounded wildcards
  • Java Generics: What is PECS?
    • This discusses the "Producer extends Consumer super" principle
    • Effective Java 2nd Edition, Item 28: Use bounded wildcards to increase API flexibility


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 Lists and it will return the same type of List, as long as the Lists 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!!!).

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜