Varargs对象处理奇怪

时间:2011-02-15 21:13:10

标签: java variadic-functions

我认为我不理解varargs如何处理传入的对象:

public class NoSense {

public static void someMethod(String a, Object... things) {

    System.err.println("a->" + a);

    System.err.println(things.getClass().getName());

    for (Object object : things) {
        System.err.println("thing->" + object);
    }


}


public static void main(String[] args) {
    String[] x = new String[] { "what", "is", "up?" };
    NoSense.someMethod("1", x);
    NoSense.someMethod("2", x, "extra");
}

}

结果

a->1
[Ljava.lang.String;
thing->what
thing->is
thing->up?
a->2
[Ljava.lang.Object;
thing->[Ljava.lang.String;@4d20a47e
thing->extra

为什么它将第一个集视为字符串数组,第二个集作为对象数组引用?

3 个答案:

答案 0 :(得分:2)

为了保持向后兼容性,varargs是编译器尝试解决方法调用的最后一件事。由于可以将呼叫NoSense.someMethod("1", x);解析为someMethod(String a, Object[] things),因此可以解决此问题。它可以这样做,因为数组类型是协变的。

然而,调用NoSense.someMethod("2", x, "extra");无法解析为someMethod(String a, Object[] things),因此使用varargs创建new Object[]{x, "extra"},然后将其作为thing参数传递。

答案 1 :(得分:1)

因为String[]引用可以通过数组协方差隐式转换为Object[]。编译器不需要使用varargs,所以它没有。

强制使用varargs,我们可以转换为Object

    NoSense.someMethod("1", (Object) x);

现在Object不能隐式转换为Object[],因此编译器会将其包装在数组中。

来自JLS的第15.12.4.2节:

  

如果使用k!= n实际参数表达式调用m,或者,如果使用k == n实际参数表达式调用m,并且第k个参数表达式的类型不与T兼容[],然后对参数列表(e1, ... , en-1, en, ...ek)进行评估,就像它被写为(e1, ..., en-1, new T[]{en, ..., ek})一样。

答案 2 :(得分:1)

因为第一个之后的所有参数都被认为是要存储在varargs数组中的值。但是,Java只考虑将数组作为特殊情况传递的情况,并将其用作varargs值。

案例1: 只有一个值传递给Object []的varargs。该值为String []。 Java将其视为特殊情况并直接传递给数组。

案例2: 两个值传递给Object []的varargs。第一个值是String []类型,第二个值是String类型。由于传递了多个值,因此不是特殊情况。因此,vargargs参数是一个Object [](就像你定义的那样),第一个元素是传递的字符串数组,第二个元素是字符串。