Захват универсального символа Java "?"ограничение запрещает изменение значения - PullRequest
0 голосов
/ 08 декабря 2018

У меня есть это:

    List<String> list = new ArrayList<>();
    list.add("ok");
    list.add("123");
    List<?> list1 = list; // What is the point of disallow modify?
    list1.add("xyz");//compile error
    List list2 = list;
    list2.add(123);//runtime exception

Странно, что:

List<?> list1 = list; // What is the point of disallow modify?
list1.add("xyz");//compile error

Почему это не позволяет мне писать элемент, даже совпадения типов?Я полагаю, что делает "list1" только для чтения, без разрешения на запись?

Как понять эту ошибку компиляции?Большое спасибо.

Ответы [ 4 ]

0 голосов
/ 08 декабря 2018

List<?> можно использовать только как справочную декларацию.Это способ сообщить компилятору, что он может содержать любой тип списка, но я не буду ничего добавлять к списку.

public void printMyList(List<?> mylist){
  mylist.forEach(item->System.out.println(item)); // works fine
  mylist.add("abcd"); //compilation error
}

Компилятор предотвращает это, потому что есть вероятность, что вы в конечном итоге поместите неправильный тип вlist.

Иногда допускается изменение в случае подстановочного знака, если он используется вместе с super:

public void printMyList(List<? super Car> mylist){
  mylist.add(new Toyota()); //works fine
}

Это говорит компилятору принять список типа Car или любой супер тип Car.Добавление Автомобиля, Тойото или Форда, которые являются подтипом Автомобиля, прекрасно в этом случае.

0 голосов
/ 08 декабря 2018

List<?> означает, что List содержит неизвестный тип, и это может быть любой тип во время выполнения.Таким образом, вы не можете присвоить ему List<String> на этапе компиляции, это небезопасно.

Предположим, вам разрешено добавлять элементы к нему:

List<String> list = new ArrayList<>();
List<?> list1 = list;
list1.add("123"); // it's ok for an list to and string "123", but it's not type safe for list1 to add string "123", since it contains an unknown type at run time.
0 голосов
/ 08 декабря 2018

При приведении типов нет «только для чтения».Единственное, что вы делаете, это изменяете универсальный тип, то есть компилятор будет жаловаться на различияЕсли мы разберем код, у вас получатся два разных результата из-за интерпретации компилятором.

Первый:

List<?> list1 = list;

То, что вы сделали, - это "преуменьшение" a List<String> доподстановочный знак List<?>.Это означает, что что-либо вызовет ошибку компиляции просто потому, что он не может знать, каким должен быть / будет подстановочный знак.(вот почему добавление String привело к ошибке компиляции).

Во втором примере вы использовали «raw-type»:

List list2 = list;

Raw-type не заботитуниверсальные типы, как и компилятор в этом случае.Вот почему не было выброшено исключение, так как каждый типизированный параметр просто по умолчанию равен Object (который является базовым классом каждого класса в Java).Следовательно, добавление целого числа (123), которое также является объектом, вполне допустимо для компилятора.Однако во время выполнения выдается исключение, так как типы не совпадают.Именно по этой причине использование raw-типов считается плохой практикой, так как такие проблемы трудно найти / решить.

0 голосов
/ 08 декабря 2018

List<?> означает, что это список, но мы не знаем во время компиляции, что в нем.

Хотя в этом случае мы можем доказать, что это List<String>, большинствовремя, когда мы не будем знать, является ли это List<String> или List<Integer> или List<Animal>.И, конечно, добавление Integer к List<String> довольно опасно, поэтому Java остановит его во время компиляции.

...