Я считаю, что это связано с контекстами вызова. и расширяющий справочник конверсия.
По сути, в этом контексте вызова тип аргумента 0
в Arrays.asList(0)
может быть заключен в Integer
, а затем расширен до Number
. Когда это происходит, Arrays.asList(0)
имеет возвращаемый тип List<Number>
. С помощью того же процесса List<Number>
можно преобразовать в List<? extends Number>
, прежде чем использовать в качестве аргумента для внешнего Arrays.asList(..)
.
Это эквивалентно использованию явных аргументов типа в Java 7.
List<List<? extends Number>> xs = Arrays.<List<? extends Number>>asList(Arrays.<Number>asList(0));
В Java 7 тип выражения одинаков независимо от того, где оно используется, независимо от того, является ли оно отдельным выражением или используется в выражении присваивания.
В Java 8 появились поли-выражения, в которых тип выражения может зависеть от целевого типа выражения.
Например, в следующем выражении присваивания
List<Number> numbers = Arrays.asList(1);
Тип выражения Arrays.asList(1)
— это возвращаемый тип вызываемого метода, который полностью зависит от параметра универсального типа. В этом случае этот аргумент типа будет выведен как Integer
, потому что значение 1
можно преобразовать в Integer
посредством преобразования упаковки (примитивы нельзя использовать с дженериками). Таким образом, тип выражения List<Integer>
.
В Java 7 это выражение присваивания не будет компилироваться, потому что List<Integer>
нельзя присвоить List<Number>
. Это можно исправить, предоставив явный аргумент типа при вызове asList
List<Number> numbers = Arrays.<Number>asList(1);
в этом случае вызов метода ожидает аргумент Number
для своего первого параметра, и значение 1
удовлетворяет этому.
В Java 8 выражением присваивания является поливыражение
Выражение вызова метода является поливыражением, если выполняются все следующие условия:
Вызов появляется в контексте назначения или в контексте вызова (§5.2, §5.3).
Если вызов квалифицирован (то есть любая форма MethodInvocation
, кроме первой), то вызов опускается TypeArguments
слева от идентификатора.
Вызываемый метод, как определено в следующих подразделах, является универсальным (§8.4.4) и имеет возвращаемый тип, в котором упоминается хотя бы один из параметров типа метода.
Будучи поливыражением, на него может влиять тип переменной, которой оно назначается. И вот что происходит. Универсальный тип Number
влияет на аргумент типа, выведенный при вызове Arrays.asList(1)
.
Обратите внимание, как это не сработает в следующем примере.
List<Number> numbers = ...;
List<Integer> integers = ...; // integers is not a poly expression
numbers = integers; // nope
Так что это не ковариация, но в некоторых местах мы получаем некоторые из ее преимуществ.
person
Sotirios Delimanolis
schedule
12.06.2014
Arrays.asList(0)
вернетList<Integer>
, аArrays.asList()
из этого вернетList
, элементами которого являютсяList<Integer>
, мне кажется, что назначениеList<List<? extends Number>>
на самом деле будет правильным... Хотя я почти наверняка что-то неправильно понимаю - person awksp   schedule 12.06.2014List<List<? extends Number>> ys = Arrays.<List<? extends Number>asList(Arrays.asList(0));
. Это показывает, что даже в Java 7 назначение является правильным и является только проблемой ограниченного вывода типа. - person Holger   schedule 13.06.2014