【问题标题】:When overloading compiler does not prefer primitive to Object only in case of varargs parameter presence仅在存在可变参数参数的情况下,重载编译器不喜欢原始对象而不是对象
【发布时间】:2013-07-13 17:53:57
【问题描述】:

请您帮我理解为什么 testVargArgsAutoboxingPriority 的第一次调用编译失败?

在第二次调用的情况下,编译器能够通过优先选择原始(第一个参数)而不是 Object 来选择正确的方法,但在添加可变参数后编译器无法再进行选择。

失败消息是

\jdk1.6.0_45\bin\javac.exe ocjp6/AutoBoxingOldStyleVarargsPriority.java
ocjp6\AutoBoxingOldStyleVarargsPriority.java:7: reference to testVargArgsAutoboxingPriority is ambiguous, both method testVargArgsAutoboxing
Priority(java.lang.Integer,boolean...) in ocjp6.AutoBoxingOldStyleVarargsPriority and method testVargArgsAutoboxingPriority(int,boolean...)
in ocjp6.AutoBoxingOldStyleVarargsPriority match
      testVargArgsAutoboxingPriority( 5, true ); // the line compilation fails
      ^
1 error

完整的代码清单是

package ocjp6;

public class AutoBoxingOldStyleVarargsPriority
{
   public static void main( final String[] args )
   {
      testVargArgsAutoboxingPriority( 5, true ); // the line compilation fails
      testVargArgsAutoboxingPriority( 5 );
   }

   private static void testVargArgsAutoboxingPriority( Integer b, boolean... c )
   {}
   private static void testVargArgsAutoboxingPriority( int b, boolean... c )
   {}

   private static void testVargArgsAutoboxingPriority( Integer b )
   {}
   private static void testVargArgsAutoboxingPriority( int b )
   {}
}

【问题讨论】:

    标签: java overloading primitive variadic-functions autoboxing


    【解决方案1】:

    答案在JLS - 15.12.2. Compile-Time Step 2: Determine Method Signature 和上面的@TheNewIdiot 答案中。这里有更详细的解释:

    对于方法:

    private static void testVargArgsAutoboxingPriority( Integer b ) {}
    private static void testVargArgsAutoboxingPriority( int b ) {}
    

    编译器只需要第一阶段就可以知道要调用哪个方法。在第一阶段,它不会混合盒装类型和原始类型。

    但是方法:

    private static void testVargArgsAutoboxingPriority( Integer b, boolean... c ) {}
    private static void testVargArgsAutoboxingPriority( int b, boolean... c ) {}
    

    包含可变参数,编译器需要进入第三阶段尝试区分它们。但在第三阶段,已经无法区分盒装类型和对应的原始类型了。

    【讨论】:

    • 感谢您的帮助和您的时间!
    【解决方案2】:

    根据JLS 15.12.2 Compile-Time Step 2: Determine Method Signature

    确定适用性的过程始于确定可能适用的方法 (§15.12.2.1)。

    流程的其余部分分为三个阶段,以确保与 Java SE 5.0 之前的 Java 编程语言版本兼容。阶段是:

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

    这保证了在 Java SE 5.0 之前在 Java 编程语言中有效的任何调用都不会因为引入可变数量方法、隐式装箱和/或拆箱而被认为是模棱两可的。但是,变量 arity 方法的声明(第 8.4.1 节)可以更改为给定方法方法调用表达式选择的方法,因为变量 arity 方法在第一阶段被视为固定 arity 方法。例如,在已经声明 m(Object) 的类中声明 m(Object...) 会导致不再为某些调用表达式(例如 m(null))选择 m(Object),如 m(Object[] ) 更具体。

    第二阶段(第 15.12.2.3 节)执行重载决议,同时允许装箱和拆箱,但仍排除使用可变参数方法调用。如果在此阶段没有找到适用的方法,则处理继续到第三阶段。

    这确保了一个方法永远不会通过可变的方法调用来选择,如果它可以通过固定的方法调用来应用的话。

    第三阶段(第 15.12.2.4 节)允许将重载与可变参数方法、装箱和拆箱相结合。

    【讨论】:

    • 感谢您的帮助和您的时间!
    猜你喜欢
    • 2018-08-22
    • 1970-01-01
    • 1970-01-01
    • 2019-10-26
    • 2023-03-10
    • 1970-01-01
    • 2014-01-13
    • 2017-03-13
    • 2019-10-03
    相关资源
    最近更新 更多