То, каково различие между <E, расширяет Число> и <Число>?

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

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

и

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

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

36
задан unj2 5 May 2010 в 02:28
поделиться

2 ответа

Первый позволяет обрабатывать List, List и т.д. Второй - нет.

Дженерики в Java инвариантны. Они не ковариантны, как массивы.

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

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

См. также

49
ответ дан 27 November 2019 в 05:54
поделиться

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

Предыдущий метод (метод с ) является общим методом , то есть он может принимать различные типы List s , и он вернет тот же тип List , если List s являются списками чего-то что расширяет число , например Список <Целое число> .

Пример:

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 подтипом List (это не так !!!).

12
ответ дан 27 November 2019 в 05:54
поделиться
Другие вопросы по тегам:

Похожие вопросы: