了解 Java 中 varargs 的意外行为

2022-09-04 22:58:12

我正在阅读这个答案,它说

另请注意,使用显式数组参数调用泛型 vararg 方法可能会以静默方式产生与预期不同的行为:

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

类似的行为在这个答案gotcha 3中得到了解释:

int[] myNumbers = { 1, 2, 3 };
System.out.println(ezFormat(myNumbers));
// prints "[ [I@13c5982 ]"

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
[I@7852e922,

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

tVarargs ==========
[[I
1
[[I@4e25154f,

tVarargs ==========
[Ljava.lang.Integer;
3
[Ljava.lang.Integer;@70dea4e,[Ljava.lang.Integer;@70dea4e,[Ljava.lang.Integer;@70dea4e,
  • 注意传递给结果,创建单个 2 维数组 wit 单个元素。但是,此数组的类型是什么?intarrtVarargs[[I
  • 此外,传递给还会导致创建包含单个数组元素的一维数组intarrobjVarargs()[Ljava.lang.Object
  • 对于休息,它创建具有与传递的元素一样多的一维数组 - 所需的行为。

有人能对前两种行为有更多的了解吗?这两种不同的行为还是相同的行为,我的意思是它们背后有不同或相同的原因。深入地讲,这些原因是什么?是否有任何其他情况会导致不同的意外行为?


答案 1

这两种行为是由同一问题引起的 - 泛型类型参数和变量都只能保存引用类型。基元(如 )不是引用类型,因此将数组传递给 varargs 方法(如果它是或并不重要)会导致该方法接受具有单个元素的数组,而该单个元素就是数组。ObjectintintObject ... aT ... sint

因此,您可以将其视为包含单个行的二维数组(即)。intint[][]

请注意,您有一个拼写错误,导致输出混乱。它应该是 ,而不是tVarargs(T ... s)System.out.print(i + ",");System.out.print(s + ",");

修复此问题后,这两种方法将为输入生成相同的输出:Integer[]

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

输入输出的差异源于这样一个事实:在 中,varargs 数组的类型是 ,而在它里面 (当 是 一个 ,数组的类型是一个)。int[]objVarargs(Object ... a)Object[]tVarargs(T ... s)T[]Tint[]int[][]

BTW,是二维数组的类名(即 )。[[Iintint[][]


答案 2

推荐