为什么带签名(primitive,wrapper)和(primitive,primitive)的两个方法会导致方法调用(包装器,原语)不明确?

时间:2014-01-04 16:59:15

标签: java jdk1.6

这只是一个练习,但我无法弄清楚这种模糊性:

private static void flipFlop(String str, int i, Integer iRef) {
System.out.println(str + "ciao");
}

private static void flipFlop(String str, int i, int j) {
System.out.println(str + "hello");
}

public static void main(String[] args) {
flipFlop("hello", new Integer(4), 2004);
}

它说:

  

方法flipFlop(String,int,Integer)对于类型是不明确的   测试

我猜想第二个参数会被解包到 int ,所以第二个flipFlop方法就是选择。

3 个答案:

答案 0 :(得分:14)

如果您喜欢阅读,here is the relevant portion of the Java Language specification描述了如何解决方法。

但基本上你的第三个参数可以解释为原始包装或自动装箱包装,编译器无法弄清楚你想要什么。两种方法都是“ maximally specific ”以使用JLS术语。

答案 1 :(得分:10)

好吧,我已经仔细研究了JLS,我相信这应该可以解决你可能遇到的任何疑问。

这是原始问题:

public class Main {
    private static void flipFlop(int i, Integer iRef) {
        System.out.println("Method 1");
    }

    private static void flipFlop(int i, int j) {
        System.out.println("Method 2");
    }

    public static void main(String[] args) {
        flipFlop(new Integer(4), 2004);
    }
}

正如在另一个答案中指出的那样:这失败了,因为编译器无法决定使用什么重载。

但是你可能认为这没有任何意义。在这种情况下,编译器可以决定使用什么方法:

public class Main {
    private static void flipFlop(Integer y) {
        System.out.println("ciao");
    }

    private static void flipFlop(int j) {
        System.out.println("hello");
    }

    public static void main(String[] args) {
        flipFlop(new Integer(6));
        flipFlop(6);
    }
}

理性告诉我们,当您有值X + Y时,两个方法分别采用Y + XY + {{1}并且你知道YX是可以互换的,那么这意味着后一种方法更具体。

这两者之间的区别在JLS中有所描述。我在下面提供了整个工作流程,但重要的是:

首先,编译器将查看具有相同签名的方法,而禁止装箱/取消装箱。在我们的第二个例子中,这不会引起任何问题,但是在我们的第一个例子中,这并没有返回一个令人满意的方法,因为它们都没有将Y作为第一个参数。

当失败时,编译器继续进行第二步,允许装箱/拆箱。这应该解决我们对第一个参数的问题,但现在引起第二个参数的歧义,因为现在不确定你是指使用Integer的过载还是使用int的过载

这最终会导致模糊的方法调用。

15.12.2. Compile-Time Step 2: Determine Method Signature

  
      
  1. 第一阶段(§15.12.2.2)执行重载解析而不允许装箱或拆箱转换,或使用变量arity方法调用。如果在此阶段没有找到适用的方法,则处理继续到第二阶段。

  2.   
  3. 第二阶段(§15.12.2.3)执行重载解析,同时允许装箱和拆箱,但仍然排除使用变量arity方法调用。如果在此阶段没有找到适用的方法,则处理继续到第三阶段。

  4.         

    如果在适用性测试的三个阶段之一中确定了几种适用的方法,则选择最具体的方法,如§15.12.2.5部分所述。

15.12.2.5. Choosing the Most Specific Method

  

如果方法调用是可访问且适用的,并且没有其他方法适用且可访问且严格更具体,则该方法被称为最大程度地特定于方法调用。

     

有可能没有最具体的方法,因为有两种或更多种方法是最具体的。在这种情况下:

     
      
  • 如果所有最具体的特定方法都具有覆盖等效(§8.4.2)签名,则:( ......一些规则来决定选择谁...)

  •   
  • 否则,我们说方法调用不明确,并且发生编译时错误。

  •   

答案 2 :(得分:0)

由于auto-boxing,您的第2004int也适用于Integer,这就是编译器无法决定使用哪种方法的原因。