关于varargs参数的困惑

时间:2014-01-07 13:11:56

标签: java variadic-functions

我对这段代码非常困惑:

class A {}
class B extends A {}

public class ComingThru  {
    static String s = "-";

    static void sifter(A[]... a2) { 
      s+="1"; 
    }

    static void sifter(B[]... b1) { 
      s+="2"; 
    }

    static void sifter(Object o) { 
      s+="4"; 
    }

    public static void main(String[] args) {
        A[] aa = new A[2];
        B[] ba = new B[2];
        sifter(aa,ba);
        System.out.println(s);
    }   
}

它输出为-1,但是由于找不到匹配的函数,应该有编译错误。

6 个答案:

答案 0 :(得分:2)

不,这不会给出编译错误。因为有一个完美的方法签名匹配调用,因为B也是A.这就是所谓的继承。如果再次检查代码,

class A {}
class B extends A {}

上面的代码使它能够编译和执行。

static void sifter(A[]... a2) { 
      s+="1"; 
    }

上面的方法可以通过传递可变长度的A类数组或其子类型(即A的子类,即B)来调用

答案 1 :(得分:1)

匹配方法是static void sifter(A[]... a2),因为B扩展A. 这就是为什么你没有得到编译错误。

如果你看得更深(即编译/反编译),你会看到在编译的字节码中有以下内容。

    static void sifter(A a[][]) {...}

    static void sifter(B b[][]) {...}

    static void sifter(Object o) {...}

    public static void main(String args[])
        {
            A aa[] = new A[2];
            B ba[] = new B[2];
            sifter(new A[][] {
                aa, ba
            });
            System.out.println(s);
        }

然后它更清楚为什么它工作正常,以及为什么它调用它调用的方法。

答案 2 :(得分:1)

Liskov substitution principle

  

可替代性是面向对象编程的一个原则。它指出,在计算机程序中,如果S是T的子类型,则类型T的对象可以用类型S的对象替换(即,类型S的对象可以替换类型为T的对象。

因此,您可以将B作为A传递给A期望的方法并找到匹配项。

 static void sifter(A[]... a2) 

答案 3 :(得分:1)

找到匹配的方法

static void sifter(A[]... a2) { s+="1"; }

将调用此方法,因为A的层次结构较高,并且可以在其中捕获B的引用。

这就是输出为"-1"

的原因

答案 4 :(得分:0)

由于B扩展A,它将与此函数匹配

 `static void sifter(A[]... a2) { s+="1"; }` //means any number of arrays of type A can be accepted and B is of type A.

如果删除它,您将收到编译错误。

答案 5 :(得分:0)

这可以帮助您理解您是否将此类重命名为此类。

class Fruit {}
class Apple extends Fruit {}

由于Apple是Fruit,因此调用需要Fruit数组的方法(static void sifter(Fruit[]... a2)

是完全有效的。