web-dev-qa-db-ja.com

Java 3ドットパラメーター(可変引数)の引数が渡されなかったときの動作またはnull

私はこれを試して、Javaから奇妙な動作を得ました、誰かがこれを私に説明できますか?

_boolean testNull(String... string) {
    if(string == null) {
        return true;
    } else {
        System.out.println(string.getClass());
        return false;
    }
}

boolean callTestNull(String s) {
    return testNull(s);
}
_

次に、テストケースがあります:

_    @Test
    public void test_cases() {
        assertTrue(instance.testNull(null)); // NULL
        assertFalse(instance.testNull()); // NOT NULL
        assertFalse(instance.callTestNull(null)); // NOT NULL
    }
_

問題は、パラメータnulltestNull()を直接呼び出すと、trueが返されますが、nullcallTestNull()を呼び出す場合ですtestNull()を呼び出す_は、パラメーターがnullではなく空の配列であることを通知します。

54
Jaiwo99

問題は、パラメータnullで直接testNull()を呼び出すと、trueが返されることですが、testNull()を呼び出すnullでcallTestNull()を呼び出すと、パラメータがnullではなく空の配列であることがわかります。

はい。 compile-time typeof Stringの引数で呼び出すと、コンパイラーはca n'tString[]であるため、文字列配列でラップします。したがって、この:

String x = null;
testNull(x);

以下と同等です:

String x = null;
testNull(new String[] { x });

この時点で、(誤解を招く名前の)stringパラメーターはnull以外の値を持ちます。代わりに、唯一の要素がnull参照であるサイズ1の配列を参照します。

ただし、メソッド呼び出しでnullリテラルを直接使用すると、String[]に直接変換できるため、ラッピングは実行されません。

JLSセクション15.12.4.2 から:

呼び出されるメソッドが可変アリティメソッドmである場合、必然的にn> 0の仮パラメータを持ちます。 mの最終的な仮パラメータは、何らかのTに対して必ず型T []を持ち、mは必然的にk≥0の実引数式で呼び出されます。

Mがk≠nの実引数式で呼び出されている場合、またはm = k = nの実引数式で呼び出されており、k番目の引数式の型が代入互換でない場合T []を使用すると、引数リスト(e1、...、en-1、en、...、ek)は、(e1、.. 。、en-1、new | T [] | {en、...、ek})、ここで| T [] | T []の消去(§4.6)を示します。

(エンファシス鉱山。)

強調したのは、引数のコンパイル時の型がnull型ではなくStringであるときにonlyのみがラップされる理由です。

58
Jon Skeet