Ответ 1
Преобразование захвата было разработано для создания подстановочных знаков (в дженериках), ?
полезно.
Предположим, что мы имеем следующий класс:
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), в ней четко говорится:
Преобразование захвата - это то, что позволяет компилятор для изготовления заполнителя имя типа для захваченного шаблона, так что вывод типа может сделать это это тот тип.
Надеюсь, это поможет вам.