【问题标题】:Understanding unexpected behaviors of varargs in Java了解 Java 中可变参数的意外行为
【发布时间】:2018-11-13 13:07:22
【问题描述】:

我正在阅读this 的答案,上面写着

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

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

this answer gotcha 3 中解释了类似的行为:

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

可变参数仅适用于引用类型。自动装箱不适用于基元数组。以下作品:

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,
  • intarr 传递给tVarargs 的通知会导致创建单个二维数组 [[I单个元素。但是,这个数组的类型是什么?
  • 此外,将intarr 传递给objVarargs() 会导致创建一维数组 [Ljava.lang.Object,其中包含单个数组元素
  • 对于其余部分,它会创建一维数组,其中包含与传递一样多的元素 - 所需的行为。

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

【问题讨论】:

  • 我不知道是什么让你感到困惑。 Type... 只是 Type[] 但允许我们将 Type 的参数作为列表传递,而不是手动将其包装到数组中。 &lt;T&gt; 仅限于引用类型(它不能表示像int 这样的原始类型),这意味着T... 因为T[] 不能是int[]。如果您传递int[] 数组,那么T 可以使用的最具体的对象类型就是数组本身。所以因为T 现在是int[] T... 就像int[]... 导致int[][] (这就是[[I 所代表的)。 Object... 只是 Object[] 数组,这就是您在其他方法中看到的

标签: java


【解决方案1】:

这两种行为是由同一个问题导致的——泛型类型参数和Object 变量都只能包含引用类型。原语(例如int)不是引用类型,因此将int 数组传递给可变参数方法(不管它是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) 中,可变参数数组的类型是Object[],而在tVarargs(T ... s) 中是T[](当Tint[],数组的类型是int[][])。

顺便说一句,[[I 是二维int 数组的类名(即int[][])。

【讨论】:

    猜你喜欢
    • 2016-05-24
    • 2020-03-07
    • 1970-01-01
    • 1970-01-01
    • 2011-12-01
    • 1970-01-01
    • 2014-06-22
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多