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

Перегрузка массивов varargs, выбор метода

У меня есть два перегруженных метода: foo и bar

//Object[]... vs Integer[]...
public static String foo(Object[]... args)  { return "Object[] args"; }
public static String foo(Integer[]... args) { return "Integer[] args";}

//Object... vs Integer[]...
public static String bar(Object... args) {return "Object args";}
public static String bar(Integer[]... args) {return "Integer[] args";}

Теперь, когда я использую их как:

Integer[] i = { 5 };
System.out.println(foo(i));//Object[]... vs Integer[]...
System.out.println(bar(i));//Object... vs Integer[]...

Я получаю

Integer[] args
Object args

Вот вопрос: почему у нас есть 2 разных выхода?
Integer[] может быть неявно отбрасываться как на Object, так и на Object[].

4b9b3361

Ответ 1

Это, в основном, компилятор, решающий вызывать наиболее специфический метод среди всех.

Когда вы вызываете

System.out.println(foo(i));//Object[]... vs Integer[]...

он выберет foo(Integer[]... args)

Потому что во время выполнения JVM делегирует вызов методу с аргументом Integer[][] и not method с Object[][] param, как указано varags. Поскольку более конкретным будет метод вызова с Integer [] [], а не Object [] [].


В более позднем заявлении, когда вы вызываете

System.out.println(bar(i));//Object... vs Integer[]...

он перейдет к bar(Object... args)

Снова с помощью varags тип param будет Object [], а не Object [] []. Опять же, компилятор вызовет наиболее специфический метод, который будет иметь Object... args.

Если вы измените подпись метода, удалив varags следующим образом:

   //Object... vs Integer[]...
    public static String bar(Object args) {

        return "Object args";
    }

    public static String bar(Integer[] args) {
        return "Integer[] args";
    }

то вы заметите, что он вызовет bar(Integer[] args), поскольку он более специфичен для вызова метода.

Точнее, чем JLS Subtyping среди типов массивов,

  • Если S и T являются ссылочными типами, тогда S [] > T [], если S > T.
  • Объект > Объект []

Это означает, что вызов Integer [] будет выполнен с использованием метода Integer [] [], а не Object [] []. Где в качестве вызова Integer [] будет сделан объект Object [], а не Integer [] [].

См. здесь для выбора наиболее конкретного метода.

Ответ 2

В первом случае тип args фактически является Integer [] [], т.е. ваш массив был помещен в другой массив с помощью varargs. Компилятор выбирает версию Integer [], потому что это наиболее специфический тип.

Во втором случае args == я и является Integer []. В этом случае компилятору приходилось выбирать между его завершением в новом массиве, чтобы вызвать версию Integer []... или просто придать Integer [] объекту []. Он выбрал вторую, потому что это правило.

Мораль истории: не перегружайте методы varargs - это запутывает.