传递无参数或null时的Java 3点参数(varargs)行为

Jai*_*o99 54 java ellipsis variadic-functions

我试过这个并从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);
}
Run Code Online (Sandbox Code Playgroud)

然后我有测试用例:

    @Test
    public void test_cases() {
        assertTrue(instance.testNull(null)); // NULL
        assertFalse(instance.testNull()); // NOT NULL
        assertFalse(instance.callTestNull(null)); // NOT NULL
    }
Run Code Online (Sandbox Code Playgroud)

现在的问题是,如果我打电话testNull()直接与参数null,我会true回来,但如果调用callTestNull()null,它调用testNull(),它告诉我该参数不为空,但空数组.

Jon*_*eet 58

问题是如果我直接使用参数null调用testNull(),我将返回true,但如果使用null调用callTestNull()调用testNull(),它会告诉我参数不是null,而是空数组.

是.如果使用编译时类型为的参数调用它String,则编译器知道它不能是a String[],因此它将其包装在字符串数组中.所以这:

String x = null;
testNull(x);
Run Code Online (Sandbox Code Playgroud)

相当于:

String x = null;
testNull(new String[] { x });
Run Code Online (Sandbox Code Playgroud)

此时,(误导性命名)string参数将具有非空值 - 相反,它将引用大小为1的数组,其唯一元素是空引用.

但是,当您null在方法调用中直接使用文字时,它可以直接转换为String[],因此不执行包装.

JLS第15.12.4.2节:

如果被调用的方法是变量arity方法m,则它必须具有n> 0个形式参数.对于某些T,m的最终形式参数必然具有类型T [],并且必须使用k≥0个实际参数表达式来调用m.

如果使用k≠n实际参数表达式调用m,或者,如果使用k = n实际参数表达式调用m并且第k个参数表达式的类型不与T []赋值兼容,则参数列表(e1,...,en-1,en,...,ek)被评估为好像被写为(e1,...,en-1,new | T [] | {en,... ,ek}),其中| T [] | 表示T []的擦除(第4.6节).

(强调我的.)

我强调的是为什么包装发生在参数的编译时类型而String不是null类型时.