Почему компилируется предоставление явных аргументов типа для не общего метода или конструктора?

При создании экземпляров ArrayLists я привык видеть такой код

ArrayList arr = new ArrayList(); 

или

 ArrayList arr = new ArrayList(); 

однако сегодня я столкнулся с экземпляром ArrayList, который выглядит так:

 ArrayList arr = new ArrayList(); 

что происходит, и почему это дает предупреждение о небезопасных операциях?

Редактировать:

Да, нашел ссылку. См. JLS §15.12.2.1 – Определение потенциально применимых методов :

Если вызов метода включает явные аргументы типа, а элемент – общий метод, то количество аргументов типа равно количеству параметров типа метода.

  • Это предложение подразумевает, что не общий метод может быть потенциально применим к вызову, который предоставляет аргументы явного типа. Действительно, это может оказаться применимым. В таком случае аргументы типа просто игнорируются.

Акцент мой.

Также см. JLS §15.9.3 – Выбор конструктора и его аргументов для понимания того, как вызов конструктора разрешен. В нем также упоминается, что вышеупомянутый процесс применяется для разрешения.


Оригинальный ответ:

Такой тип вызова часто требуется, когда у вас есть общий конструктор, и компилятор не может вывести правильные аргументы типа. Например, рассмотрите приведенный ниже код:

 class Demo { public  Demo(X[] arg1, X arg2) { // initialization code System.out.println(arg1.getClass()); System.out.println(arg2.getClass()); } } 

Предположим, вы вызываете этот конструктор следующим образом:

 Demo demo = new Demo(new String[2], new Integer(5)); 

Вы могли бы подумать, что вывод типа должен завершиться неудачно, поскольку аргументы типа должны иметь одинаковые типы. Здесь мы передаем типы String и Integer . Но это не так. Компилятор описывает тип X как:

 Object & Serializable & Comparable> 

Теперь вам может потребоваться, чтобы параметр типа был выведен как просто Object , тогда в этом случае вы можете указать явные аргументы типа, как в приведенном ниже коде:

 Demo demo = new Demo(new String[2], new Integer(5)); 

Это похоже на то, как вы даете явный аргумент типа при вызове метода.

Теперь, в вашем коде, вы указали явные аргументы типа, но для его экземпляра используется необработанный тип classа:

 ArrayList arr = new ArrayList(); 

– это явный аргумент типа для конструктора, и компилятор будет в порядке с ним. Но проблема в том, что вы создаете исходный тип ArrayList , и именно здесь компилятор дает ваше безотлагательное предупреждение. Если вы измените этот код на:

 ArrayList arr = new ArrayList<>(); 

Предупреждение исчезнет. Но так как конструктор ArrayList не является общим конструктором, аргумент типа просто игнорируется конструктором. На самом деле здесь нет аргументов типа.

Как ни странно, это также компилируется:

 public static void test() { } public static void main(String... args) { Main.test(); } 

… хотя test() – это не общий метод.

Я только что попробовал:

 ArrayList arr = new ArrayList(); 

И получил такое же предупреждение (не ошибка!). Похоже, компилятор игнорирует 1 генерики после new ключевого слова и перед ArrayList . Это похоже на письмо:

 ArrayList arr = new ArrayList(); 

1 Я не уверен, действительно ли это «игнорирует», я буду рад, если кто-то подтвердит / исправит меня

Код, он ничего не делает!

 int a = new Integer(5); 

Он также компилируется, но генерирует предупреждение о «неиспользуемых дженериках».

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

Обратите внимание, что генерические файлы скомпилированы в любом случае, поэтому на уровне байт-кода он, вероятно, не будет выглядеть иначе. Я заглянул в затмение, чтобы превратить это в ошибку вместо предупреждения, но не повезло.

ОБНОВИТЬ

Этот ответ сводится к тому же, что и к другому, который в настоящее время находится на +5, так почему мой нисходящий? Пожалуйста, оставьте комментарий, если вы используете downvote.