Понимание неожиданного поведения varargs в Java

Я читал этот ответ, где он говорит

Также обратите внимание, что вызов универсального метода vararg с явным параметром массива может молча привести к другому поведению, чем ожидалось:

public <T> void foo(T... params) { ... }
int[] arr = {1, 2, 3};
foo(arr); // passes an int[][] array containing a single int[] element

Подобное поведение объясняется в этом ответе, полученном 3:

int[] myNumbers = { 1, 2, 3 };
System.out.println(ezFormat(myNumbers));
// prints "[ [[email protected] ]"

Varargs работает только со ссылочными типами. Автобокс не применяется к массиву примитивов. Следующие работы:

Integer[] myNumbers = { 1, 2, 3 };
System.out.println(ezFormat(myNumbers));
// prints "[ 1 ][ 2 ][ 3 ]"

Я попробовал более простые примеры:

private static <T> void tVarargs(T ... s)
{
    System.out.println("\n\ntVarargs ==========");
    System.out.println(s.getClass().getName());
    System.out.println(s.length);
    for(T i : s)
        System.out.print(s + ",");
}

private static void objVarargs(Object ... a)
{
    System.out.println("\n\nobjVarargs =========== ");
    System.out.println(a.getClass().getName());
    System.out.println(a.length);
    for(Object i : a)
        System.out.print(i + ",");
}

int[] intarr = {1,2,3}; 
Integer[] Intarr = {1,2,3};

objVarargs(intarr);
objVarargs(Intarr);

tVarargs(intarr);
tVarargs(Intarr);

Это печатает

objVarargs =========== 
[Ljava.lang.Object;
1
[[email protected],

objVarargs =========== 
[Ljava.lang.Integer;
3
1,2,3,

tVarargs ==========
[[I
1
[[[email protected],

tVarargs ==========
[Ljava.lang.Integer;
3
[Ljava.lang.Integer;@70dea4e,[Ljava.lang.Integer;@70dea4e,[Ljava.lang.Integer;@70dea4e,
  • Обратите внимание, что передача intarr в tVarargs приводит к созданию одного двумерного массива [[I with single element. Тем не менее, какие типы этого массива?
  • Кроме того, передача intarr в objVarargs() приводит к созданию [Ljava.lang.Object массива [Ljava.lang.Object содержащего один элемент массива.
  • Для отдыха он создает 1-D массив с таким количеством элементов, которое было передано - желаемое поведение.

Может кто-то пролить больше света на первые два поведения? Являются ли эти два разных поведения или одинаковыми, я имею в виду разные или одинаковые причины. Каковы эти причины, в глубине? Есть ли другие случаи, приводящие к другому неожиданному поведению?

Ответ 1

Эти два поведения являются результатом одной и той же проблемы - и параметры универсального типа, и переменные Object могут содержать только ссылочные типы. Примитив (такой как int) не является ссылочным типом, поэтому передача массива int в метод varargs (и не имеет значения, является ли он Object... a или T... s) приводит к тому, что метод принимает массив имеющий один элемент, и этот единственный элемент является массивом int.

Поэтому вы можете рассматривать его как двумерный массив int (то есть int[][]), содержащий одну строку.

Обратите внимание, что у вас есть опечатка в tVarargs(T... s) которая приводит к запутанному выводу. Это должен быть System.out.print(i + ","); , а не System.out.print(s + ",");

Как только вы исправите это, оба метода выдают один и тот же вывод для ввода Integer[]:

[Ljava.lang.Integer;
3
1,2,3,

Разница в выходных данных для ввода int[] objVarargs(Object... a) с тем, что в objVarargs(Object... a) тип массива varargs - Object[], а в tVarargs(T... s) T[] (и когда T - это int[], тип массива - это int[][]).

Кстати, [[I - это имя класса двумерного массива int (то есть int[][]).