ошибка с varargs и перегрузка?

Кажется, что ошибка в реализации Java varargs. Java не может отличить соответствующий тип, когда метод перегружен различными параметрами vararg.

Это дает мне ошибку The method ... is ambiguous for the type ...

Рассмотрим следующий код:

 public class Test { public static void main(String[] args) throws Throwable { doit(new int[]{1, 2}); // <- no problem doit(new double[]{1.2, 2.2}); // <- no problem doit(1.2f, 2.2f); // <- no problem doit(1.2d, 2.2d); // <- no problem doit(1, 2); // <- The method doit(double[]) is ambiguous for the type Test } public static void doit(double... ds) { System.out.println("doubles"); } public static void doit(int... is) { System.out.println("ints"); } } 

в документах говорится: «Вообще говоря, вы не должны перегружать метод varargs, или программистам будет сложно выяснить, какая перегрузка вызвана».

однако они не упоминают эту ошибку, и программистам это не сложно, это компилятор.

мысли?

EDIT – компилятор: Sun jdk 1.6.0 u18

3 Solutions collect form web for “ошибка с varargs и перегрузка?”

Об этом обсуждается на форумах Sun.

Никакого реального разрешения нет, просто отставка.

Varargs (и автоматическое боксирование, которое также приводит к сложному поведению, особенно в сочетании с varargs), были заперты позже в жизни Java, и это одна из областей, где это видно. Так что это скорее ошибка в спецификации, чем в компиляторе.

По крайней мере, это приводит к хорошим (?) Вопросам трюка SCJP.

Проблема в том, что она неоднозначна.

 doIt(1, 2); 

может быть вызовом doIt(int ...) или doIt(double ...) . В последнем случае целые литералы будут продвигаться до double значений.

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

EDIT – соответствующая часть JLS – « 15.12.2.5 Выбор самого конкретного метода », но у меня болит голова.

Я думаю, что рассуждение будет состоять в том, что void doIt(int[]) не является более конкретным (или наоборот), чем void doIt(double[]) потому что int[] не является подтипом double[] (и наоборот). Поскольку две перегрузки одинаково специфичны, вызов неоднозначен.

Напротив, void doItAgain(int) более специфичен, чем void doItAgain(double) потому что int является подтипом double соответствии с JLS. Следовательно, вызов doItAgain(42) не является двусмысленным.

EDIT 2 – @finnw прав, это ошибка. Рассмотрите эту часть 15.12.2.5 (отредактировано для удаления неприменимых случаев):

Один метод члена переменной arty с именем m более специфичен, чем другой метод члена переменной arty с тем же именем, если:

Один метод-член имеет n параметров, а другой имеет k параметров, где n ≥ k. Типы параметров метода первого элемента – T1,. , , , Tn-1, Tn [], типы параметров другого метода – U1,. , , , Uk-1, Uk []. Пусть Si = Ui, 1 < = i <= k. Затем:

  • для всех j от 1 до k-1, Tj <: Sj и,
  • для всех j от k до n, Tj <: Sk

Примените это к случаю, когда n = k = 1, и мы видим, что doIt(int[]) более специфично, чем doIt(double[]) .


Фактически, для этого есть отчет об ошибке, и Sun признает, что это действительно ошибка, хотя они определили приоритет как «очень низкий» . Ошибка теперь отмечена как Исправлена ​​в Java 7 (b123).

Интересно. К счастью, есть несколько способов избежать этой проблемы:

Вместо этого вы можете использовать типы обертки в сигнатурах метода:

  public static void doit(Double... ds) { for(Double currD : ds) { System.out.println(currD); } } public static void doit(Integer... is) { for(Integer currI : is) { System.out.println(currI); } } 

Или вы можете использовать дженерики:

  public static  void doit(T... ts) { for(T currT : ts) { System.out.println(currT); } } 
  • Правила перегрузки Java
  • Почему мой журнал в пространстве имен std?
  • Перегружен main () в C ++?
  • Как перегруженный метод выбирается, когда параметр является буквальным нулевым значением?
  • перегрузка constexpr
  • Можно ли переопределить не виртуальный метод?
  • Обработка перегрузки std :: endl?
  • Должны ли вы объявлять методы с использованием перегрузок или необязательных параметров в C # 4.0?
  • Что является прецедентом для перегрузки функций-членов в ссылочных квалификаторах?
  • Функции с аргументами const и перегрузкой
  • Перегрузка с другим возвращаемым типом в Java?
  • Давайте будем гением компьютера.