为什么foo(1,2,3)没有被传递到可变参数方法foo(Object...)作为Integer[]?

18
请看下面的代码行:

public static void main(String[] args)  {
    foo(1,2,3);
    System.out.println("-------------------------------------");
    foo(new Integer(1), new Integer(2), new Integer(3));
    System.out.println("-------------------------------------");
    foo(new Integer[]{1,2,3});
    System.out.println("-------------------------------------");
    foo(new Integer[] {new Integer(1), new Integer(2), new Integer(3)});
}

public static void foo(Object... bar) {
    System.out.println("bar instanceof Integer[]:\t" + (bar instanceof Integer[]));
    System.out.println("bar[0] instanceof Integer:\t" + (bar[0] instanceof Integer));
    System.out.println("bar.getClass().isArray():\t" + bar.getClass().isArray());
}

这段代码的输出结果是:
bar instanceof Integer[]:   false
bar[0] instanceof Integer:  true
bar.getClass().isArray():   true
-------------------------------------
bar instanceof Integer[]:   false
bar[0] instanceof Integer:  true
bar.getClass().isArray():   true
-------------------------------------
bar instanceof Integer[]:   true
bar[0] instanceof Integer:  true
bar.getClass().isArray():   true
-------------------------------------
bar instanceof Integer[]:   true
bar[0] instanceof Integer:  true
bar.getClass().isArray():   true

这让我有点困惑!我不明白为什么在 foo(1,2,3) 的情况下,bar instanceof Integer[] 是假的。

如果在这些情况下 bar 不是 Integer[] 的实例,那它还能是什么实例呢?

2
我认为第一和第二个应该是对象数组而不是整数数组。 - Roger Dwan
3
因为您可以将例如String类型的值传递给可变参数(varargs),所以它最初应该是Object[]而不是Integer[]。对于最后两个,您明确地传递了Integer[],因此您的条件现在将为真。 - SomeJavaGuy
这是一个有趣的问题!一个建议:尝试添加一个 foo(new int[]{1,2,3}); 的测试。结果将从令人困惑变得奇怪! - Lii
@Lii 哦,好吧 :D int[] 将被解释为单个对象,而不是包装所有的 int!很棒的添加! - ParkerHalo
5个回答

24
  • foo(1,2,3);

这一行代码将 1, 2, 和 3 自动装箱为 Integer 类型,由于它们是 Object 子类型,因此会创建一个由三个 Integer 组成的 Object[] 数组。由于数组类型为 Object[] 而不是 Integer[],所以会得到 false 的结果。


  • foo(new Integer(1), new Integer(2), new Integer(3));

在这里,没有自动装箱,但最终你仍然会得到一个由三个 Integer 组成的 Object[]数组。同样地,Object[] 不是 Integer[] ,所以会得到 false 的结果。


  • foo(new Integer[]{1,2,3});

这里只有一个参数,不像前两种情况,那里有三个参数被包装到一个数组中。因此,在运行时,比较 bar instanceof Integer[] 将返回 true,因为整数就是你实际拥有的对象。


  • foo(new Integer[] {new Integer(1), new Integer(2), new Integer(3)});

与前一个代码行相同 - 在运行时,你将检查所提供的数组 Integer[] 是否是 Integer 数组,这是 true


4
好的,我现在明白我的错误了。我(错误地)假设由仅包含IntegersObject[]将是一个Integer[](仔细考虑后,这当然是错误的!)。谢谢! - ParkerHalo

5
根据Java语言规范:
instanceof运算符的结果为true,如果RelationalExpression的值不为null,并且引用可以转换(§15.16)为ReferenceType而不引发ClassCastException。
在您的情况下,Object[]参数无法转换为Integer[],因此返回false。

给演员们:这就是我首先遇到这个问题的原因 ;) - ParkerHalo

3
当bar不是整数数组时,这是因为它是一个对象数组,正如您在foo方法签名中指定的那样:Object... argsObject[] args的语法糖,当解析到此方法时,编译器将创建一个对象数组。
为了始终拥有一个整数数组,您可以将foo方法的签名更改为foo(Integer... args)

3

可变参数只是用于创建和传递数组的语法糖。由于您将方法定义为

public static void foo(Object... bar) 

如果你以foo(1,2,3)foo(new Integer(1), new Integer(2), new Integer(3))的方式调用方法,Java会为你创建一个Object[]数组。

然而,你也可以将自己创建的数组传递给使用可变参数的方法。在这种情况下,Java不会为你创建新的数组,而只是传递你创建的数组。在最后两个调用中,你显式地创建了一个Integer[]数组。


2
在调用 foo(1,2,3); 的情况下,编译器(在此情况下是 javac)生成的代码为 foo(new Object[]{new Integer(1), new Integer(2), new Integer(3)})javac 应用 VarargsAutoboxing 规则。编译器生成一个 Object 数组,因为 Object... 表示 Object[]。因此,bar 不是 Integer[] 的实例。它只是语法糖。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接