SCJP问题:Java方法重载与var-args。背后的原理是什么?

7
为什么以下程序抛出异常?
public class MainClass{
  public static void main(String[] argv){
       callMethod(2);
  }
  public static void callMethod(Integer... i){
       System.out.println("Wrapper");
  }
  public static void callMethod(int... i){
       System.out.println("Primitive");
  }

方法callMethod(Integer[])对于MainClass类型来说是有歧义的

好的,我可以看到如果另一个方法被注释掉,两个方法都可以使用,但我也知道如果原始类型与方法输入的类型不完全匹配,会发生什么。

首先尝试的是扩大原始类型。因此,如果有第三种方法:

      public static void callMethod(long i){
       System.out.println("long");
      }

这段代码会打印出long

第二件事情是将基本数据类型装箱。所以如果有一个方法接受整数(Integer),那么它将被调用。

第三个优先级是可变参数(VAR-ARGS)。

根据以上优先规则,我希望第二个优先级生效。也就是说,我期望int类型会被包装成Integer类型,并调用(Integer...)方法。但很明显这并没有发生,反而抛出了异常。

是否有人能看出来并解释为什么该优先级规则在此例中不适用呢?

谢谢!

1个回答

9
你说的没错,扩宽转换在装箱之前,装箱又在可变参数之前。
但是你似乎将第一个方法视为callMethod(Integer i)而不是callMethod(Integer... i)。由于两种方法都使用了可变参数,因此存在优先级tie。也就是说,没有一种方法单独满足装箱的条件,但两种方法都满足可变参数的条件。
请记住,将类型扩展后再装箱是非法的(尽管在发布这个答案之前我进行了一些研究,并发现装箱然后扩展是合法的)。同样,您不会获得装箱然后可变参数的行为;编译器直接跳到可变参数步骤,并看到两个带有可变参数的方法。
编辑:我应该澄清,如果没有歧义,您将获得装箱-然后-可变参数的行为。换句话说,如果只有一个callMethod(),并且它采用Integer... i,则会得到“Wrapper”。

我有点认为它尝试了三种方法,第一个“可调用”的方法将被调用。虽然该方法需要(Integer ... i),但我有点期望将其装箱为Integer会使该方法“可调用”。但是,正如你所说,似乎后续的“var-arg-ization”也被考虑在内。干杯! - Markos Fragkakis

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