2016-09-14 3 views
1

8 сигнатура метода Java выглядит следующим образом:Java общие методы, подстановочные Список возврата типа

public static <E extends CharSequence> List<? super E> m(List<E> list); 

И где-то в коде, вызов метода:

result = m(list); 

Предположим, что я создать аргумент list, как следующим образом:

List<String> list = new ArrayList<>(); 

Мой вопрос, почему result может быть Jus t raw List, и не может быть даже List<Object>?

+0

Я спрашиваю, почему мой «результат» не может быть «списком » или «Список », например. Это может быть просто «Список». – bladekp

+0

Почему вы используете подстановочный знак в качестве возвращаемого типа? Это довольно странная вещь ... – fge

+0

@fge Это метод библиотеки, а не мой. – bladekp

ответ

2

вызова метода с List<String> в качестве аргумента как вызов следующий метод:

public static List<? super String> m(List<String> list) { ... } 

Рассмотрим следующий исходный код:

List<String> list = new ArrayList<>(); 
List<? super String> result = m(list); 

Это вызывает вышеупомянутый метод и сохраняет возвращенную значение в переменную result - которая вводится точно с типом возвращаемого метода.

Вопрос: какие переменные - или лучше какие типы - можете ли вы присвоить эту переменную? Поэтому мы говорим о совместимости присваивания.

Рассмотрим эти задания:

List<String> result1 = result; // compiler error: type mismatch (not assignable) 
List<Object> result2 = result; // compiler error: type mismatch (not assignable) 

List result3 = result; // ok 
List<?> result4 = result; // ok 

List<? super String> result5 = result; // ok 
List<? extends Object> result6 = result; // ok 

Чтобы понять природу этой ошибки, вы должны знать, что генерики инвариантную. Это означает, что тип List<String>не является подтипом List<Object> - хотя типы String и Object имеют такую ​​иерархию подтипов.

Итак, что мы пытаемся здесь:

  1. Назначение List<? super String> к List<String> => не удается, не подтипов
  2. не Присвоить List<? super String> к List<Object> => не удается, не подтипов
  3. Присвоить a List<? super String> до List => успешно, потому что использование необработанных типов отказывается от проверки типа вообще
  4. Присвойте List<? super String>List<?> => Преуспевает, потому что List<?> является супертипом всех List<...>
  5. Назначьте List<? super String> к List<? super String> => преуспевает, потому что ... ну ...
  6. Присвоить List<? super String> к List<? ectends Object> => преуспевает, потому что List<? ectends Object> является по существу то же самое, что и List<?>.

Обратите внимание, что попытка назначить List<? super String> к List<? super CharSequence> или List<? extends CharSequence> также потерпит неудачу. Они не находятся в иерархии подтипов.

Почему это так? Компилятор не может гарантировать, что фактический список был создан с типом, который соответствует ограничению ? super/extends CharSequence.

1

Причина, по которой вы не можете этого сделать, состоит в том, что Java-дженерики не являются ковариантными. То есть List<Object> является не a super-class List<String>. Подпись метода вашего метода m, тем не менее, позволит вернуть List<String>, а затем у вас будет List<Object> типизированная ссылка, указывающая на List<String>. Поскольку информация об универсальном типе недоступна во время выполнения, это не приведет к немедленному возникновению исключения, но это может привести к ошибкам типа в несвязанных местах.

Например, предположим, что m реализуется следующим образом:

private static List<CharSequence> theResult = new ArrayList<>(); 

public static <E extends CharSequence> List<? super E> m(List<E> list) { 
    theResult.addAll(list); 
    return theResult; 
} 

Затем, используя свой метод следующим образом будет устанавливаю не- CharSequence объекта к List<CharSequence>:

List<Object> os = m(someList); 
os.add(new Object()); 

К счастью, выше делает не компилировать.

Смежные вопросы