Подтвердить что ты не робот

Какой метод называется? (Integer... a) vs. (int a, int b)

Я только что узнал об очень интересном трюке Java:

void method1(Integer... a){
}

Итак, вы можете дать этому методу столько целых чисел, сколько хотите.

Теперь, если у меня есть подобный (перегруженный) метод, например:

void method1(int a, int b){

}

Какой метод выполняется, когда я выполняю следующую строку:

method1(1, 2);

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

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

Итак, кто-нибудь знает немного больше информации об этом?

4b9b3361

Ответ 1

Чтобы определить, какой метод следует вызывать, компилятор просматривает следующий список, как описано в JLS # 5.3 и JLS # 15.12.2:

  • преобразование идентичности (§5.1.1) = > method1(int a, int b)
  • расширение примитивного преобразования (§5.1.2)
  • расширение ссылочного преобразования (§5.1.5)
  • преобразование в бокс (§5.1.7), за которым следует расширенное ссылочное преобразование == > method1(Integer... a)
  • преобразование для распаковки (п. 5.1.8), за которым следует расширенное преобразование примитива.

В вашем случае применяется первая точка и вызывается method1(int, int).

(Чтобы быть более точным, ваш метод использует varags и имеет более низкий приоритет, чем простое преобразование в бокс. Другими словами, если бы был method1(Integer a, Integer b), он был бы до method1(Integer... a) в иерархии)

Почему так? Комментарий в 15.12.2 дает подсказку:

Это гарантирует, что любые вызовы, которые были действительны на языке программирования Java до Java SE 5.0, не считаются неоднозначными в результате внедрения методов переменной arity, неявного бокса и/или распаковки.

Ответ 2

Второй метод выигрывает. Согласно Java Language Specification (pdf),

Первая фаза (§15.12.2.2) выполняет разрешение перегрузки без разрешения преобразование бокса или распаковки или использование вызова метода переменной arity.

Если на этом этапе обнаружен применимый метод, этот метод побеждает; дальнейший поиск не выполняется. В вашем случае это второй метод, потому что первый - это метод переменной arity, который также требует бокса.

Ответ 3

Будет вызван метод method1 (int a, int b). Просто проверил код байта для этого - здесь Integer... a на самом деле является Integer[] a Для подробного преобразования проверьте преобразование присваивания

Ответ 4

Я почти догадываюсь, но, как сказал thinksteep, Integer... фактически рассматривается как массив Integer, что подразумевает, что вызов вашего метода должен был бы сделать два принуждения, чтобы он соответствовал первому методу (бокс int до Integers и обрабатывать список аргументов как массив, а не просто два разных аргумента). Принимая во внимание, что для обеспечения соответствия второму методу не требуются принуждения.

Хорошо, я вижу, что некоторые другие уже цитировали JLS с большей спецификой, чем я предоставил, в то время как я печатал это.

Ответ 5

varargs имеет наименее приоритетный. Если никакой другой метод сопоставления не найден, то он вызывает только его. Это похоже на случай SWITCH по умолчанию.