В чем разница между <E extends Number> и <Number>? - PullRequest
34 голосов
/ 05 мая 2010

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

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

и

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

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

Ответы [ 2 ]

48 голосов
/ 05 мая 2010

Первый допускает process из List<Integer>, List<Double> и т. Д. Второй - нет.

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

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

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

Смотри также

12 голосов
/ 05 мая 2010

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

прежний метод (тот, который с <E extends Number>) - это универсальный метод , означающий, что он может принимать различные типы List s и он вернет тот же тип List, пока List s являются списками что-то , что простирается 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> (это не !!!).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...