7

以下のコードで

class A {
    public void v(int... vals) {
        System.out.println("Super");
    }
}

class B extends A {
    @Override
    public void v(int[] vals) {
        System.out.println("Sub");
    }
}

次にnew B().v(1, 2, 3);//print Sub rather than Super、ばかげているがうまく機能する呼び出しを行うことができます。私がに変更Bした場合

class B {
    public void v(int[] vals) {
        System.out.println("Not extending A");
    }
}

への呼び出しnew B().v(1, 2, 3);は無効になります。と呼ぶ必要がありますがnew B().v(new int[]{1, 2, 3});、なぜですか?

4

2 に答える 2

7

JDK 1.7 では、どちらの例もコンパイルされません。

2 番目のバージョンがB拡張されない理由は簡単にわかります - when does not extendsAでは、varargs の表示がまったくないため、コンパイラが 3 つのint引数の引数リストを単一の に変換する必要がある理由はありませんint[]。より興味深い状況は、B do が拡張する場所Aです。

コンパイラは、varargs を使用しないv(int[] vals)署名を見つけます。仕様には、他の宣言の 1 つ (複数の宣言がある可能性があります) が varargs を使用しているかどうかを調べるために継承チェーンを検索する必要があると言うものは何もありません。お使いのバージョンの JDK 1.6 に表示されるという事実は、それがコンパイラのバグであり、その後修正されたことを示唆しています。(JDK 1.6.0_39 のバグも再現しました。)

B.v()基本的に、varargs スタイルの構文で呼び出すことができるようにする場合は、varargsB.v()を使用して宣言する必要があります。もちろん、コンパイル時の型が になるように変更すると、次のようにA動作します。

A a = new B();
a.v(1, 2, 3);

または(気分が悪い):

((A) new B()).v(1, 2, 3);

とにかくコンパイルすると、-Xlint次の警告が表示されることに注意してください。B

Test.java:14: warning: v(int[]) in B overrides v(int...) in A; overriding method
 is missing '...'
    public void v(int[] vals) {
                ^
于 2013-07-31T20:50:50.677 に答える
0

vararg の動作方法が原因で動作しません。

あなたの方法が次の場合:

foo(int... par)

foo(new int[]{1, 2, 3});
foo(1, 2, 3);

これらは両方とも有効なメソッド呼び出しです。ただし、その逆は機能しません。

あなたの方法が次の場合:

bar(int[] par)

bar(new int[]{1, 2, 3}); // Valid
bar(1, 2, 3); // Invalid!

2 回目の呼び出しは無効になります。メソッドに vararg パラメータがある場合、配列を受け入れることができます。配列パラメーターがある場合、パラメーターのシーケンスではなく、配列のみを受け入れることができます!

于 2013-07-31T21:24:28.610 に答える