为什么类型提升优先于重载方法的varargs

Shi*_*ney 6 java overloading variadic-functions

public class Test
{
    public static void printValue(int i, int j, int k)
    {
        System.out.println("int");
    }

    public static void printValue(byte...b)
    {
        System.out.println("long");
    }

    public static void main(String... args)
    {
        byte b = 9;
        printValue(b,b,b);
    }
}
Run Code Online (Sandbox Code Playgroud)

上面代码的输出是"int".但它应该是"长"因为字节类型参数函数已经存在.但是这里的程序正在将字节值提升为int,但情况并非如此.

有人可以澄清这里发生了什么吗?

Jon*_*eet 11

JLS 15.12.2是这里要看的规范的相关部分.特别是 - 强调我的:

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

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

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

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

    这确保了如果通过固定的arity方法调用适用,则永远不会通过变量arity方法调用来选择方法.

  • 第三阶段(§15.12.2.4)允许重载与变量arity方法,装箱和拆箱相结合.

在您的情况下,第一阶段找到匹配而不使用变量arity方法调用或装箱,因此这就是结果.如规范中所述,这基本上是为了向后兼容.


CKi*_*ing 5

在重载方法的情况下,可变参数方法将始终是编译器最后选择的方法。将 a 提升byte为 an int(加宽转换)将优于采用 var-arg 参数的方法。

这背后的原因是语言需要向后兼容。旧功能将优先于新功能。理解JLS关于变量参数的一个简单方法是,加宽将击败拳击,而拳击将击败 var-args。