Java 3 点参数 (varargs) 行为时没有参数或空值

2022-08-31 15:01:52

我试过这个,并从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
    }

问题是,如果我直接用参数调用,我会回来,但如果用,哪个调用,它告诉我参数不是空的,而是空数组。testNull()nulltruecallTestNull()nulltestNull()


答案 1

问题是,如果我直接用参数null调用testNull(),我会得到true,但是如果用null调用callTestNull(),它调用testNull(),它告诉我参数不是空的,而是空数组。

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

String x = null;
testNull(x);

等效于:

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

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

但是,当您直接在方法调用中使用文本时,可以直接转换为 ,因此不执行包装。nullString[]

来自 JLS 第 15.12.4.2 节

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

如果 m 是用 k 个≠ n 个实际参数表达式调用的,或者,如果用 k = n 个实际参数表达式调用 m,并且第 k 个参数表达式的类型与 T[] 不兼容,则参数列表 (e1, ..., en-1, en, ..., ek) 的计算方式就像它被写成 (e1, ..., en-1, 新|T[]|{ en, ..., ek }),其中 |T[]|表示 T[] 的擦除 (§4.6)。

(强调我的。

我所强调的位是为什么包装发生在参数的编译时类型是,而不是空类型。String


答案 2