В чем разница между <E extends Number> и <Number>?

В чем разница между этим объявлением метода:

public static <E extends Number> List<E> process(List<E> nums){

а также

 public static List<Number> process(List<Number> nums){

Где бы вы использовали первый?

2 ответа

Решение

Первый позволяет process из List<Integer>, List<Double>и т. д. Второй нет.

Обобщения в Java инвариантны. Они не ковариантны, как массивы.

То есть в Java, Double[] это подтип Number[], но List<Double> НЕ подтип List<Number>, List<Double>Однако, является List<? extends Number>,

Существуют веские причины для инварианта дженериков, но также extends а также super тип часто необходимы для гибкости подтипирования.

Смотрите также

Последний метод (тот, без <E extends Number>) будет принимать только параметр точно типа List<Number> и будет ли он всегда возвращать List<Number>, Например, он не примет List<Integer>,

Бывший метод (тот, с <E extends Number>) является общим методом, то есть он может принимать различные типы Listи он вернет тот же тип ListДо тех пор, пока Lists списки чего-то, что расширяется 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:
http://java.sun.com/docs/books/tutorial/java/generics/subtyping.html

См. Также Как преобразовать список наследуемых объектов в коллекцию объектов в Java? Оба вопроса действительно о дженериках и подтипах, например, List<Integer> это подтип List<Number> (это не!!!).

Другие вопросы по тегам