如何解释这种看似不一致的Java varargs行为呢?

时间:2014-11-26 06:28:55

标签: java arrays generics variadic-functions

如果我编写Java方法

public static void f(int... x) {
    for (int a: x) {
        System.out.println(a);
    }
}

然后我可以通过

调用此方法
f(1, 2, 3);

以及

f(new int[]{1, 2, 3});

并且两个电话的处理方式完全相同。但是,这两个电话

Arrays.asList(1, 2, 3)              // (a) produces a three-element Integer list

Arrays.asList(new int[]{1, 2, 3})   // (b) produces a one-element list of Integer arrays

不一样。 JLS状态中的The section on evaluating arguments" m 的最终形式参数必须具有某些T[]"的类型T。那么为什么不是最终的形式参数"如果(b)上面不是一个整数数组,它会创建一个三元素列表,如情况(a)?

我唯一能想到的是Arrays.asList是通用的,关于类型兼容性的东西(在JLS第15.12.4.2节中提到)在这里发挥作用,但我可以&# 39;我完全把手指放在JLS中的实际句子中,使两种情况不同。

JLS中的评论讨论了为了处理参数化类型和在具有擦除泛型的Java虚拟机中发生的数组类型之间的相互作用,需要仔细制作这些语义。但我们最终得到的是我的函数fArrays.asList看起来表现不一致。在前一种情况下,我可以"解包"或"打包"我的args和一切都是一样的;在后一种情况下,两种情况不同。

这是如何用语言律师的术语解释的?

2 个答案:

答案 0 :(得分:5)

Arrays.asList被定义为具有参数T...,并且正文将其视为T[]类型的一个参数。但是,T 必须是引用类型(与任何类型参数一样),int不是引用类型。因此,没有办法使new int[]{...}与数组兼容以实现varargs。 (并且结果将是List<int>,这是不允许的。)唯一的选择是将其视为单个对象,因此T这里将是int[],这是一个参考类型,该函数将返回List<int[]>

我认为这就是原因,虽然我仍然需要查找确切的语言。它可能涉及类型推理规则,我还没有掌握。

然而,我确实试过这个:

List x = Arrays.asList(new int[]{1, 2, 3});
List y = Arrays.asList(new Integer[]{1, 2, 3});
System.out.println(x.size());   
System.out.println(y.size());   

(请注意,我故意使用List原始类型,这是我在实际代码中不会做的事情。输出:

1
3

答案 1 :(得分:2)

    Arrays.asList(1, 2, 3);

1 2 3被自动装箱到Integer对象,然后放在Object []

    Arrays.asList(new int[]{1, 2, 3});

强制将3个整数转换为原始的int数组。

Arrays.asList()预计Object[],因此会将您的int[]数组放入单个元素Object[]