Ваш вопрос обоснован. Короче говоря, ссылка на метод действительно использует исходный тип (или должен использовать необработанный тип), и причина, почему создание общих массивов запрещена, по-прежнему применяется при использовании ссылок на методы, следовательно, возможность тихо создавать функцию, создающую общий массив явно нарушает намерение дизайна языка.
Причина, по которой создание общего массива запрещена, заключается в том, что наследование типа массива, связанное с эрой до Generics, несовместимо с системой типового типа. То есть Вы можете написать:
IntFunction<List<String>[]> af = List[]::new; // should generate warning
List<String>[] array = af.apply(10);
Object[] objArray = array;
objArray[0] = Arrays.asList(42);
List<String> list = array[0]; // heap pollution
На этом месте, следует подчеркнуть, что в отличие от некоторых ответов здесь, компилятор делает не выполнить определение типа на выражении List[]::new
вывести общий тип List<String>
элемента. Это легко доказать, что родовое создание массива до сих пор запрещено:
IntFunction<List<String>[]> af = List<String>[]::new; // does not compile
Поскольку List<String>[]::new
является незаконным, было бы странно, если бы List[]::new
был принят без предупреждения путем выводя его эффективно незаконной List<String>[]::new
быть.
JLS §15.13 ясно сказано:
Если метод опорного выражение имеет вид ArrayType::
new
, то ArrayType должен обозначать тип, который reifiable (§4.7), или ошибка во время компиляции имеет место.
Это уже означает, что List<String>[]::new
является незаконным, потому что List<String>
не reifiable, в то время как List<?>[]::new
является законным, так как List<?>
является reifiable и List[]::new
является законным, если мы считаем List
быть сырье типа, как сырье типList
можно отменить.
Тогда §15.13.1 гласит:
Если метод опорного выражение имеет вид ArrayType::
new
, один смысловой метод считается. Метод имеет единственный параметр типа int
, возвращает ArrayType и не имеет условия throws
. Если n = 1, это единственный потенциально применимый метод; в противном случае нет потенциально применимых методов.
Другими словами, поведение выражения List[]::new
выше такой же, как если бы вы написали:
IntFunction<List<String>[]> af = MyClass::create;
…
private static List[] create(int i) {
return new List[i];
}
за исключением того, что метод create
только отвлеченный. И действительно, с этим явным объявлением метода есть только необработанные типы предупреждений по методу create
, но нет непроверено предупреждения о преобразовании List[]
в List<String>[]
по ссылке метода. Поэтому понятно, что происходит в компиляторе в случае List[]::new
, где метод, использующий необработанные типы, является только условным, т. Е. Не существует в исходном коде.
Но отсутствие непроверенных предупреждения является явным нарушением JLS §5.1.9, Unchecked Conversion:
Пусть G
имя по шаблонного типа с п параметров типа.
Существует бесконтрольно преобразование из сырья класса или интерфейса типа (§4.8) G
к любому типу параметризованной формы G<T₁,...,Tₙ>
.
Существует необработанное преобразование из типа необработанного массива G[]ᵏ
в любой тип массива формы G<T₁,...,Tₙ>[]ᵏ
. (Обозначение []ᵏ
указывает тип массива из к размеров.)
Использование непроверенного преобразования вызывает время компиляции непроверенную предупреждение если все аргументы типа T
ᵢ (1 ≤ я ≤ п) являются неограниченными подстановочными знаками (§4.5.1), или непроверенное предупреждение подавляется аннотацией SuppressWarnings
(§9.6.4.5).
Таким образом, преобразование List[]
в List<?>[]
является законным, так как List
спараметрирован с неограниченным символом, но преобразование из List[]
в List<String>[]
должно произвести непроверенной предупреждения, что имеет решающее значение здесь, как использование List[]::new
не производит необработанный тип предупреждение, которое появляется с явным методом создания. Отсутствие необработанного типа предупреждений, кажется, не является нарушением (насколько я понял §4.8), и это не будет проблемой, если javac
создал необходимое предупреждение , непроверенное.
смешно ... писать 'n -> новый тест [n];' вместо 'Test [] :: new' (который в основном должен быть тем же) снова даст вам предупреждение о непроверенной компиляции – Roland
@ Roland они оба отшлифованы до того же самого точного байтового кода. Действительно интересно – Eugene
@Eugene: ну, для формальных правил, как правило, не имеет значения, чего скрывают языковые конструкции. Но компилятор явно должен выпустить предупреждение * непроверенное * здесь. – Holger