Java 10 переменная var и захват

Я читаю JEP 286, но я не понимаю эту часть:

Захватывающие переменные и типы с вложенными переменными захвата проецируются на супертипы, которые не упоминают переменные захвата. Это сопоставление заменяет переменные захвата их верхними границами и заменяет аргументы типа, ссылающиеся на переменные захвата с ограниченными подстановочными знаками (а затем повторяется). Это сохраняет традиционно ограниченный диапазон переменных захвата, которые рассматриваются только в одном заявлении.

Может ли кто-нибудь сделать мне конкретный пример в Java-коде, что это значит?

Ответ 1

var позволяет вывести тип, не обозначаемый:

var x = new Object() {
    int i = 10;
};

System.out.println(x.i); // works; 'x' has the non-denotable type of the annonymous class

Поэтому теоретически это позволит вам вывести тип подстановочных знаков. Но этот текст говорит о том, что это невозможно, потому что подстановочный знак заменяется верхней границей или новой переменной захвата в выведенном типе.

Возьмем, к примеру, этот фрагмент кода:

List<String> l1 = new ArrayList<>();
l1.add("Hello");
List<?> l2 = l1;

var x = l2.get(0);
l2.add(x); // error

Здесь вместо того, чтобы тип x был выведен на точный тип wild card, который бы скомпилировал последнюю строку. Вместо этого он выводится на верхнюю границу, которая является Object, и вы получаете сообщение об ошибке (Eclipse):

The method add(capture#2-of ?) in the type List<capture#2-of ?> is not applicable for the arguments (Object)

Где вы можете видеть, что тип x является Object.

Это часть

Это сопоставление заменяет переменные захвата верхними границами


Вторая часть

... и заменяет аргументы типа, в которых упоминаются переменные захвата с ограниченными подстановочными знаками

Говорит о такой ситуации:

List<String> l1 = new ArrayList<>();
l1.add("Hello");
List<?> l2 = l1;
var l3 = l2; // type of 'l3' is List<?>, but not the same '?' as 'l2'

l3.add(l2.get(0)); // error

Это тоже не скомпилируется, поскольку тип l3 не является тем же типом, что и тип l2, а это означает, что тип, возвращаемый из l2.get(0), не является тем же типом, который требуется l3.add(...). Ошибка здесь:

The method add(capture#2-of ?) in the type List<capture#2-of ?> is not applicable for the arguments (capture#3-of ?)

И вы видите, что обе переменные захвата различны, что означает, что тип l3 не является точно типом l2, но переменная захвата типа l2 в выведенном типе заменяется шаблоном с той же границей, для который затем создает новую переменную захвата.

Итак, для типа List<capture#1-of?> Выведенный тип - List<?>, А затем компилятор создает новую переменную захвата для этого шаблона, что дает List<capture#2-of?> (Хотя нумерация может работать по-разному на практике, ключ в том, что переменные захвата 2 различны).