Почему ArrayList может присваиваться ArrayList

#java #generics

#java #обобщения

Вопрос:

 public class Demo {
    public static void main(String[] args) {
        ArrayList<Integer> list = getList();
        System.out.println(list.toString());
        list.add(1);
        System.out.println(list.toString());
    }

    public static <T> ArrayList<T> getList(){
        ArrayList<String> strings =  new ArrayList<>();
        strings.add("qwert");
        return (ArrayList<T>) strings;
    }
}
  

Как показано в приведенном выше коде, почему разрешено присваивать ArrayList
JDK11 выводит

 [qwert]
1
  

Комментарии:

1. Я бы порекомендовал вам прочитать Generics на Java .

2. Использование (casting) похоже на сообщение компилятору «поверь мне, я знаю, что я делаю». Когда существует какой -то безопасный сценарий для приведения, компилятор не будет жаловаться, и все, что после этого, будет ошибкой программистов.

3. Кастинг здесь плохой. Проблема в том, что приведение сообщает компилятору «Я знаю лучше вас, поэтому рассматривайте это как массив целых чисел, даже если это не так»

4. Я получаю предупреждение о непроверенном приведении от компилятора Java при компиляции этого кода. Итак, компилятор все-таки предупреждает.

Ответ №1:

Почему ArrayList<T> может присваиваться ArrayList<Integer>

Это потому, что вы предоставили явное приведение типов.

Вероятно, вы не в состоянии понять, как ArrayList<Integer> list можно удерживать qwert . Опять же, это потому, что вы попросили компилятор доверять вам, что вы вкладываете Integer в него.

В конце концов, вся информация о типе удаляется, когда дело доходит до времени выполнения. Вам нужно понять концепцию удаления типа.

Ответ №2:

 return (ArrayList<T>) strings;
  

Здесь строка ArrayList напрямую не преобразуется в Integer ArrayList, вместо этого она преобразуется в T ArrayList. В соответствии с «выводом целевого типа» в документах:

 static <T> List<T> emptyList();
List<String> listOne = Collections.emptyList();
  

Этот оператор ожидает экземпляр List; этот тип данных является целевым типом. Поскольку метод emptyList возвращает значение типа List, компилятор делает вывод, что аргумент типа T должен быть строкой значения.