当超载编译器不喜欢原语对象只在可变参数的参数存在的情况下,(When overloading com

2019-10-18 09:33发布

拜托,你能帮助我理解为什么testVargArgsAutoboxingPriority的第一个电话的编译失败?

在第二呼叫编译器的情况下,能够选择由宁愿原语(第一个参数)适当的方法的对象,但编译器的可变参数的参数添加后不能进行选择的任何更多。

失败消息

\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 )
   {}
}

Answer 1:

答案就在JLS - 15.12.2。 编译时间第2步:确定方法的签名和@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 ) {}

包含可变参数的参数和编译器需要得到第三阶段试图来区分它们。 但在第三阶段是不能够再进行装箱的类型及其对应的基本类型之间的区别。



Answer 2:

按照JLS 15.12.2编译时第2步:确定方法签名 。

确定适用性的方法开始于确定潜在的可应用的方法(§15.12.2.1)。

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

第一阶段(§15.12.2.2)执行重载而不允许拳击或取消装箱转换,或使用可变元数的方法调用的。 如果在此阶段没有发现适用方法然后处理继续到第二阶段。

这保证了这是有效的在Java SE 5.0之前的Java编程语言中的任何调用并不认为是不明确引进的变量元数法,隐式装箱和/或拆箱的结果。 然而,可变元数法(§8.4.1)的声明可以改变选择用于给定方法的方法调用表达的方法中,因为可变的arity方法作为在第一阶段的固定元数的方法进行处理。 例如,在其中已经声明了米(对象)类声明米(对象...)导致米(对象),以不再被选择用于某些调用表达式(如米(NULL)),为m(对象[] )是更具体的。

第二阶段(§15.12.2.3)执行重载解析,同时允许装箱和拆箱,但仍排除使用可变元数的方法调用的。 如果在此阶段没有发现适用方法然后处理继续到第三阶段。

这确保了一种方法,通过从未可变元数的方法调用选择,如果它是适用通过固定元数的方法调用。

第三阶段(§15.12.2.4)允许重载具有可变元数的方法,拳击,和取消装箱组合。



文章来源: When overloading compiler does not prefer primitive to Object only in case of varargs parameter presence