我认为我不理解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
为什么它将第一个集视为字符串数组,第二个集作为对象数组引用?
答案 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 [](就像你定义的那样),第一个元素是传递的字符串数组,第二个元素是字符串。