tags:

views:

213

answers:

2

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?

+9  A: 

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

polygenelubricants
+2  A: 

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!!!).

Bert F