Неоднозначные методы варгара

Вот пример кода, который не компилируется:

public class Test { public static void main(String[] args) { method(1); } public static void method(int... x) { System.out.println("varargs"); } public static void method(Integer... x) { System.out.println("single"); } } 

Может ли кто-нибудь сказать мне, почему эти методы неоднозначны? Заранее спасибо.

Рассмотрим подписи метода

 public static void foo(int a) 

а также

 public static void foo(Integer a) 

Перед боксом и распаковкой вызов foo(1) не был бы двусмысленным. Для обеспечения совместимости с более ранними версиями Java вызов остается недвусмысленным. Поэтому первая фаза разрешения перегрузки не позволяет запускать бокс, unboxing или переменную arity invocation, которые были введены одновременно. Вызов переменной arity – это когда вы вызываете метод varargs, передавая последовательность параметров для последнего аргумента (а не массива).

Однако разрешение method(1) для ваших сигнатур методов допускает бокс и распаковку, потому что для обоих методов требуется вызов переменной arity. Поскольку бокс разрешен, применяются обе подписи. Обычно, когда применяются две перегрузки, выбирается наиболее конкретная перегрузка. Однако ни одна из ваших подписей не является более конкретной, чем другая (поскольку ни int ни Integer не являются подтипом другого). Поэтому method(1) вызова method(1) неоднозначен.

Вы можете сделать этот компилятор, передав вместо этого new int[]{1} .

В разрешении перегрузки используются 3 фазы ( JLS 15.2.2 ):

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

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

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

В вашем примере оба метода являются методами переменной arity, поэтому применяется третий этап.

Теперь, поскольку у нас есть два метода на выбор, мы ищем более конкретный метод.

JLS 15.12.2.5. Выбор наиболее конкретного метода говорит:

Если более чем один метод-член доступен и применим к вызову метода, необходимо выбрать один для предоставления дескриптора для отправки времени выполнения. Язык программирования Java использует правило, в котором выбран наиболее специфический метод.

Один применимый метод m1 более конкретный, чем другой применимый метод m2, для вызова с выражениями аргументов e1, …, ek, если выполняется одно из следующих утверждений:

m2 не является общим, m1 и m2 применимы при вызове переменной arity, и где первые k переменных параметров arity параметров m1 являются S1, …, Sk и первыми k переменными параметрами arity параметров m2 являются T1, … , Tk, тип Si более специфичен, чем Ti для аргумента ei для всех i (1 ≤ i ≤ k). Кроме того, если m2 имеет k + 1 параметров, то k + 1’th переменный параметр параметра arity m1 является подтипом k + 1’th переменной параметра arity параметра m2.

В вашем случае у вас есть два не общих метода, которые применимы при вызове переменной arity (т.е. оба имеют varargs). Чтобы один из методов был выбран при вызове method(1) , один из них должен быть более конкретным, чем другой. В вашем случае каждый метод имеет только один параметр и для одного из них более конкретный, чем для другого, тип этого одного параметра должен быть подтипом параметра другого метода.

Поскольку int не является Integer и Integer не является подтипом int , ни один из ваших методов более специфичен, чем другой. Следовательно, The method method(int[]) is ambiguous for the type Test ошибки The method method(int[]) is ambiguous for the type Test .

Пример, который будет работать:

 public static void method(Object... x) { System.out.println("varargs"); } public static void method(Integer... x) { System.out.println("single"); } 

Поскольку Integer является Integer Object , второй метод выбирается при вызове method(1) .

Потому что они неоднозначны. Согласно JLS, вы можете либо расширить, бокс, либо бокс, а затем расширить. В вашем примере есть два метода, которые могут быть помещены в бокс / unboxed друг с другом. Во время компиляции, хотя это не видно из-за varargs , которые всегда были не совсем ясны в java.

Даже Sun рекомендовал разработчикам не перегружать методы varargs, были ошибки в компиляторе, связанные с ним ( см. Здесь ).

Разница между int и Integer заключается в том, что Integer является типом объекта. Вы можете использовать в такой ситуации, как поиск максимального числа типа int или сравнение с целыми числами

Объект Integer уже связан с методами, подобными методу сравнения:

 public static void method(int x, int y) { System.out.println(Integer.compare(x, y)); } 

Найти больше по адресу: http://docs.oracle.com/javase/7/docs/api/

  • Вызывать прямые методы или методы с аргументами / переменными / параметрами в EL
  • Android ViewPager setCurrentItem не работает после onResume
  • Что такое «статический метод» в C #?
  • Доступ к методу из других classов objective-C
  • Могут ли переопределенные методы различаться по типу возврата?
  • Java - создание массива методов
  • Почему вызов функции требует имя параметра в Swift?
  • Обнаружить версию целевой рамок во время компиляции
  • Java: Тернар без возврата. (Для вызова метода)
  • Как вызвать метод, хранящийся в HashMap? (Java)
  • Почему метод getter и setter важен в java?
  • Давайте будем гением компьютера.