Почему тип-продвижение имеет приоритет над varargs для перегруженных методов

public class Test { public static void printValue(int i, int j, int k) { System.out.println("int"); } public static void printValue(byte...b) { System.out.println("long"); } public static void main(String... args) { byte b = 9; printValue(b,b,b); } } 

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

Пожалуйста, может кто-нибудь уточнить, что здесь происходит?

Переменные методы аргументов всегда будут последними, которые будут выбраны компилятором в случае перегруженных методов. Продвижение byte в int (расширение-преобразование) будет предпочтительнее метода, который принимает параметр var-arg.

Причина этого в том, что язык должен быть обратно совместимым. Старые функции будут иметь приоритет над новыми функциями. Простой способ понять, что JLS говорит о переменных аргументах, заключается в том, что расширение будет бить бокс, а бокс будет бить var-args.

JLS 15.12.2 – это соответствующий бит спецификации, чтобы посмотреть здесь. В частности – акцент мой:

Остальная часть процесса разделена на три этапа, чтобы обеспечить совместимость с версиями языка программирования Java до Java SE 5.0. Фазы:

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

    Это гарантирует, что любые вызовы, которые были действительны на языке программирования Java до Java SE 5.0, не считаются неоднозначными в результате внедрения методов переменной arity, неявного бокса и / или распаковки. Однако объявление метода переменной arity (§8.4.1) может изменить метод, выбранный для выражения вызова метода данного метода, поскольку метод переменной arity рассматривается как метод фиксированной arity в первой фазе. Например, объявление m(Object...) в classе, который уже объявляет m(Object) приводит к тому, что m(Object) больше не выбирается для некоторых выражений вызова (таких как m(null) ), как m(Object[]) является более конкретным.

  • Вторая фаза (§15.12.2.3) выполняет разрешение перегрузки при разрешении бокса и распаковки, но все же исключает использование вызова метода переменной arity. Если на этом этапе не обнаружен какой-либо применимый метод, обработка продолжается до третьей фазы.

    Это гарантирует, что метод никогда не выбирается при вызове метода переменной arity, если он применим посредством вызова метода фиксированной arity.

  • Третий этап (§15.12.2.4) позволяет комбинировать перегрузку с методами переменной arity, боксом и распаковкой.

В вашем случае первая фаза находит совпадение без использования метода вызова переменной arity или бокса, следовательно, это результат. Как отмечено в спецификации, это в основном для обратной совместимости.

  • Перегрузка и переопределение Java
  • Конфликт перегруженных методов с дополнительными параметрами
  • Неоднозначный вызов Varargs Java
  • перегрузка метода vs необязательный параметр в C # 4.0
  • Почему у ImmavableList Guava столько перегруженных методов ()?
  • Перегрузка функций по типу возврата?
  • Почему «избегать перегрузки метода»?
  • Перегрузка метода для нулевого аргумента
  • Дополнительные параметры?
  • Вызов функции переопределения базового classа из метода базового classа
  • Почему перегрузка метода не допускается в WCF?
  • Давайте будем гением компьютера.