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

Why is foo(1,2,3) not passed to varargs method foo(Object... ) as an Integer[]

请注意以下代码行:

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[] 的实例,那么它是什么的实例?

bar 不是整数数组的情况是因为它是您在 foo 方法签名中指定的对象数组:Object... argsObject[] args 的语法糖当解析到这个方法时,编译器将创建一个对象数组。

为了始终拥有一个整数数组,您可以将 foo 方法签名更改为 foo(Integer... args)

  • foo(1,2,3);

这个自动装箱 123Integer(s),因为它们是 Object 子类型,Object[] 数组被创建,由三个 Integer 组成。数组 Object[] 不是 Integer[],这就是为什么你得到 false.


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

在这里,没有应用自动装箱,但最后您将再次拥有一个由三个 Integer 组成的数组 Object[]。同样,Object[] 不是 Integer[],这就是你得到 false.

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

这里你有只有一个参数,不像前两种情况,你有三个包裹在一个数组中。因此,只有一个参数 Integer[],在运行时比较 bar instanceof Integer[] 将 return true,因为整数是您实际拥有的。


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

与上一个相同 - 在运行时,您将检查提供的数组 Integer[] 是否为 Integer 的数组,即 true.

在调用 foo(1,2,3); 的情况下,编译器(在本例中为 javac)生成代码 foo(new Object[]{new Integer(1), new Integer(2), new Integer(3)})

javac 应用 Varargs and Autoboxing 的规则。编译器生成一个 Object 的数组,因为 Object... 表示 Object[]。因此 bar 不是 Integer[] 的实例。它只是语法糖。

根据 Java Language Specification:

the result of the instanceof operator is true if the value of the RelationalExpression is not null and the reference could be cast (§15.16) to the ReferenceType without raising a ClassCastException.

在您的情况下,Object[] 参数无法转换为 Integer[],因此它 returns 为 false。

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

public static void foo(Object... bar) 
如果您将方法调用为 foo(1,2,3)foo(new Integer(1), new Integer(2), new Integer(3))

Java 会为您创建一个 Object[] 数组。

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