在 java 中使用具有原始类型的可变参数重载时的奇怪行为

Weird behavior when overloading using variable arguments with primitive types in java

显然我对重载、自动装箱和可变参数的工作原理了解不够。

只要涉及原始类型,程序就会出现问题。

public static void z(int a, Object...objects){
}
public static void z(Object...objects){
}
public static void main(String[] args) {
    z();    // no error
    z(4);   // Compile time Error : Ambiguous

    z2();               // No error
    z2(true, "sadas");  // Error

    // No problem with reference types
    z3();       // No error. String one called
    z3(5);      // No error. Object one called

    z4();       // Error
    z4(4);      // Error
    z4("asdas");    // Working properly
}
public static void z2(boolean b, Object...objects){
}
public static void z2(Object...objects){
}
public static void z3(String...objects){
    System.out.println("String one called");
}
public static void z3(Object...objects){
    System.out.println("Object one called");
}
public static void z4(int...objects){
    System.out.println("int z4 called");
}
public static void z4(Object...objects){
    System.out.println("Object z4 called");
}

任何人都可以解释为什么会发生这种情况吗? 我可以愉快地使用 Integer, Boolean 而不是 int, boolean 但会非常很想知道它背后的内部工作。

如果编译器无法确定应使用哪个重载方法变体,则方法调用将不会编译。

我们以z4为例:

  1. 方法调用 z4() 符合两种变体的特征。
  2. 方法调用 z4(4) 也符合两个变体的签名,因为变量可以自动装箱。
  3. 方法调用 z4("asdas") 没有歧义,因为 String 不能转换为 int

更新:解析重载方法调用规则如下:

The first phase (§15.12.2.2) performs overload resolution without permitting boxing or unboxing conversion, or the use of variable arity method invocation. If no applicable method is found during this phase then processing continues to the second phase.

...

The second phase (§15.12.2.3) performs overload resolution while allowing boxing and unboxing, but still precludes the use of variable arity method invocation. If no applicable method is found during this phase then processing continues to the third phase.

...

The third phase (§15.12.2.4) allows overloading to be combined with variable arity methods, boxing, and unboxing.

如果在同一阶段选择了多个变体,则选择最具体的一个,*但简而言之,z3(String...)z3(Object...) 更具体,而 z4(int...)z4(Object...) 同样具体。

*确定这个最具体变体的规则有些复杂(参见here

这是一个很棒的问题

现在考虑

public static void z2(boolean b, Object... objects) {
    }

    public static void z2(Object... objects) {
    }

这两种方法都有一个可变参数,这意味着它们都将在重载决策的第三个也是最后一个阶段被考虑。

记住对象 class 是 java

中所有对象的母亲

好吧,这说明了一件事

编译器可以将两者都视为对象,这将再次生成对象数组。

现在终于

void z2(boolean b, Object... objects)
    public static void z2(Object... objects) 

被视为相同的功能。

要查看可以评论

    z2(true); 
    z2(true, "sadas"); 

删除其中一个

public static void z2(boolean b, Object... objects) {
            }
Or
    public static void z2(Object... objects) {
    }

这行得通。 但是

你在参数中获取了对象

如果你是具体的,例如

   public static void z2(boolean b, String... objects) {

        }
        public static void z2(String... objects) {
        }
z2(); // No error
z2(true, "sadas"); // No error

这样就可以解决