方法重载中的原始可变参数

Primitive vararg parameters in method overloading

原始人又来了,打破规则,我以前学过。好吧,技术上不是原始的,而是由它们组成的。

我了解到,每当没有比 rest 更具体的方法时,就会出现编译时错误,就像这里发生的那样。

public static void caller(){
    z5();  // Error. Neither Integer, nor String is more specific
    z5(null);  // Error for the same reason
}
public static void z5(Integer...integers){
    System.out.println("Integer z5 called");
}
public static void z5(String...strings){
    System.out.println("String z5 called");
}

现在原始人出现了。

public static void caller(){
    z1(null);  // Error cuz [I, [J, [F all are subclass of Object.
    z1();  // SURPRISINGLY works and calls the int one. WHY?
}
public static void z1(int...integers){
    System.out.println("int z1 called");
}
public static void z1(long...longs){
    System.out.println("long z1 called");
}
public static void z1(float...floats){
    System.out.println("float z1 called");
}

此处出现预期的编译时错误。

public static void caller(){
    z1(null);  // Error
    z1();  // Error
}
public static void z1(int...integers){
    System.out.println("int z1 called");
}
public static void z1(boolean...bools){
    System.out.println("bool z1 called");
}

现在我的问题是,int[]、float[] 或任何基元数组都不是基元类型,那么为什么它们的处理方式与其他引用类型不同?

--更新--

@john16384 You don't think I read your "Possible duplicate" Varargs in method overloading in Java

那里的最佳答案是 您不能将可变参数与加宽或装箱结合使用。此外,我忘了提及,OP 的代码发布在那里,在我的 jdk 7.

上运行良好

到底发生了什么对 (int...is) & (float...fs) 但对 (Integer.. .is) & (Float...fs) 而不是 (int...is) & (boolean...bool)

引自 JLS 关于适用于多种方法时的可变参数调用:

15.12.2.5. Choosing the Most Specific Method

If more than one member method is both accessible and applicable to a method invocation, it is necessary to choose one to provide the descriptor for the run-time method dispatch. The Java programming language uses the rule that the most specific method is chosen.

The informal intuition is that one method is more specific than another if any invocation handled by the first method could be passed on to the other one without a compile-time error. In cases such as an explicitly typed lambda expression argument (§15.27.1) or a variable arity invocation (§15.12.2.4), some flexibility is allowed to adapt one signature to the other.

这里的重要部分是如何更具体地定义方法。它基本上说 int...long... 更具体,因为您可以传递给第一个方法的任何值也可以传递给第二个方法。

这也适用于您不传递任何参数的情况。 int... 将是最具体的(它甚至会认为 byte... 更具体!)。

public static void main(String[] args) {
    bla();
}

private static void bla(long... x) {}
private static void bla(int... x) {}
private static void bla(short... x) {}
private static void bla(byte... x) {}   // <-- calls this one

同时创建重载时出现错误的原因 boolean... 是现在调用哪个方法不明确,编译器在到达必须选择最具体方法的位置之前停止.