Я заметил, что JLS говорит о 5.1.10 Capture Conversion, но я не понимаю, что это такое.
Может ли кто-нибудь объяснить их мне/привести примеры?
Я заметил, что JLS говорит о 5.1.10 Capture Conversion, но я не понимаю, что это такое.
Может ли кто-нибудь объяснить их мне/привести примеры?
Преобразование захвата было разработано для создания подстановочных знаков (в дженериках), ?
полезно.
Предположим, что мы имеем следующий класс:
public interface Test<T> {
public void shout(T whatever);
public T repeatPreviousShout();
}
и где-то на нашем коде мы имеем
public static void instantTest(Test<?> test) {
System.out.println(test.repeatPreviousShout());
}
Потому что test
не является сырым test
, а поскольку repeatPreviousShout()
в "hindsight" возвращает ?
, компилятор знает, что там T
, который служит как параметр типа для test
.
Это T
для неизвестного T
, поэтому компилятор стирает неизвестный тип (для подстановочных знаков он заменяет Object
). Следовательно, repeatPreviousShout()
возвращает Object
.
Но если бы мы имели,
public static void instantTest2(Test<?> test) {
test.shout(test.repeatPreviousShout());
}
Компилятор даст нам ошибку чего-то вроде Test<capture#xxx of ?> cannot be applied
(где xxx
- число, например 337
).
Это связано с тем, что компилятор пытается выполнить проверку безопасности типа на shout()
, но поскольку он получил подстановочный знак, он не знает, что представляет T
, следовательно, он создает местозаполнитель, называемый capture.
Из здесь (теория и практика Java: дикая с дженериками, часть 1), в ней четко говорится:
Преобразование захвата - это то, что позволяет компилятор для изготовления заполнителя имя типа для захваченного шаблона, так что вывод типа может сделать это это тот тип.
Надеюсь, это поможет вам.
Параметрированный тип, включающий аргументы типа подстановочного типа, действительно является типом объединения. Например
List<? extends Number> = Union{ List<S> | S <: Number }
В 2 случаях вместо использования List<? extends Number>
Java использует захваченную версию List<S>
, где S - это только что созданная переменная типа с верхней границей Number
.
(1) http://java.sun.com/docs/books/jls/third_edition/html/expressions.html
Чтобы сузить тип выражения. Если тип выражения List<? extends Number>
, мы точно знаем, что тип среды выполнения на самом деле является List<S>
для определенного типа S (S <: Number>
). Таким образом, для более точного анализа типов используется компилятор List<S>
.
Преобразование захвата применяется к каждому выражению индивидуально; это приводит к некоторым немым результатам:
<T> void test1(List<T> a){}
<T> void test2(List<T> a, List<T> b){}
List<?> x = ...;
test1(x); // ok
test2(x, x); // error
(2) http://java.sun.com/docs/books/jls/third_edition/html/typesValues.html#4.10.2
В проверке подтипа A :< B
, где A
содержит подстановочные аргументы. Например,
List<? extends Number> :< B
<=>
Union{ List<S> | S <: Number} :< B
<=>
List<S> :< B, for all S <: Number
Таким образом, мы проверяем захваченную версию типа A