Почему я все еще могу добавить любой объект в список со ссылочным типом необработанного типа после изменения его типа объекта на универсальный?

Я объявил и инициализировал myList с необработанным ссылочным типом List и необработанным типом объекта ArrayList. Затем я повторно сослался на myList на новый универсальный ArrayList of Longs. Я думал, что добавление в этот список чего-либо, кроме Long, вызовет ошибку.

List myList = new ArrayList();
myList = new ArrayList<Long>();
myList.add(3.4d);
myList.add(4.0f);
myList.add("weird");
myList.add('w');
System.out.println(myList);

Однако это выполняется без ошибок или исключений. Насколько это законно?


person K Man    schedule 02.01.2020    source источник
comment
Базовый тип является необработанным, даже если вы определяете экземпляр с помощью Generecity. Когда вы вызываете метод добавления, вы вызываете метод добавления необработанного списка. так что с точки зрения компиляции все правильно. С другой стороны, когда код скомпилирован, дженериков больше нет, так что с точки зрения времени выполнения все правильно.   -  person alainlompo    schedule 03.01.2020
comment
Вот как работают необработанные типы. Однако включите предупреждения и обратите внимание на свой компилятор.   -  person Tom Hawtin - tackline    schedule 03.01.2020
comment
Обобщения являются полностью механизмом времени компиляции и не существуют во время выполнения, поэтому обобщения полагаются на тип времени компиляции переменной, а не на реальный тип.   -  person Slaw    schedule 03.01.2020


Ответы (2)


Если вы объявите его как List<Long>, вы получите статическую проверку типа во время компиляции. Сделайте, чтобы стереть тип, когда JVM ничего не знает об этих типах во время выполнения.

List<Long> myList = new ArrayList<>();
myList.add("foo");

Выдаст ошибку компиляции, пока:

public void breakGeneric(List list) {
    list.add("foo");
}
....
List<Long> myList = new ArrayList<>();
breakGeneric(myList);

добавит «foo» в список независимо от типа типа. Большинство IDE будут изводить вас из-за потери универсального типа.

Наличие типа в новом операторе new ArrayList<Long>() будет иметь эффект только в том случае, если вы выберете цепочку из этого оператора, т.е. new ArrayList<Long>().add("foo"). Это единственный способ, при котором общий тип только в операторе new вызовет проблемы при компиляции.

person SephB    schedule 02.01.2020

Насколько это законно?

Поскольку компилятор Java рассматривает только объявленный тип, который в данном случае является необработанным типом List:

List myList

который может содержать любой тип объекта.

Назначение myList = new ArrayList<Long>() не влияет на объявленный тип myList.

person Bohemian♦    schedule 02.01.2020
comment
Это может быть семантика, но это не совсем так. Обобщения будут влиять на анонимные объекты без объявления типа. Смотрите мой ответ, хотя это не очень полезный пограничный случай, за исключением, возможно, шаблона строителя. - person SephB; 03.01.2020
comment
@Seph нет, это совершенно верно. - person Bohemian♦; 03.01.2020
comment
Этот оператор new ArrayList<Long>().add("foo") не имеет объявленного типа, только предполагаемый, но вызовет ошибку компиляции. - person SephB; 03.01.2020
comment
@seph он имеет объявленный тип и не выводится; общий тип new ArrayList<Long>() жестко закодирован как Long. Примером встроенного выводимого типа может быть new ArrayList<>().add("");, где String — выводимый тип. Однако этот момент не имеет отношения к этому вопросу, который касается типов raw. - person Bohemian♦; 03.01.2020
comment
Ааа, именно поэтому я начал свои комментарии с it may be semantics. - person SephB; 03.01.2020