简体   繁体   English

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

[英]Java 3 dots parameter (varargs) behavior when passed no arguments or null

I tried this and get weird behavior from JAVA, can someone explain this for me? 我试过这个并从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);
}

Then I have test case: 然后我有测试用例:

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

The question is if I call testNull() directly with parameter null , I will get true back, but if call callTestNull() with null , which calls testNull() , it tells me the parameter is not null, but empty array. 现在的问题是,如果我叫testNull()直接与参数null ,我会得到true回来,但如果调用callTestNull()null ,这就要求testNull()它告诉我该参数不为空,但空数组。

The question is if I call testNull() directly with parameter null, I will get true back, but if call callTestNull() with null, which calls testNull(), it tells me the parameter is not null, but empty array. 问题是如果我直接使用参数null调用testNull(),我将返回true,但如果使用null调用callTestNull()调用testNull(),它会告诉我参数不是null,而是空数组。

Yes. 是。 If you call it with an argument with a compile-time type of String , the compiler knows that can't be a String[] , so it wraps it within a string array. 如果使用带有编译时类型 String的参数调用它,则编译器知道它不能String[] ,因此它将其包装在字符串数组中。 So this: 所以这:

String x = null;
testNull(x);

is equivalent to: 相当于:

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

At this point, the (misleadingly-named) string parameter will have a non-null value - instead, it will refer to an array of size 1 whose sole element is a null reference. 此时,(误导性命名的) string参数将具有非空值 - 相反,它将引用大小为1的数组,其唯一元素是空引用。

However, when you use the null literal directly in the method call, that's directly convertible to String[] , so no wrapping is performed. 但是,当您在方法调用中直接使用null文本时,它可以直接转换为String[] ,因此不执行包装。

From JLS section 15.12.4.2 : JLS第15.12.4.2节

If the method being invoked is a variable arity method m, it necessarily has n > 0 formal parameters. 如果被调用的方法是变量arity方法m,则它必须具有n> 0个形式参数。 The final formal parameter of m necessarily has type T[] for some T, and m is necessarily being invoked with k ≥ 0 actual argument expressions. 对于某些T,m的最终形式参数必然具有类型T [],并且必须使用k≥0个实际参数表达式来调用m。

If m is being invoked with k ≠ n actual argument expressions, or, if m is being invoked with k = n actual argument expressions and the type of the k'th argument expression is not assignment compatible with T[] , then the argument list (e1, ..., en-1, en, ..., ek) is evaluated as if it were written as (e1, ..., en-1, new |T[]| { en, ..., ek }), where |T[]| 如果使用k≠n实际参数表达式调用m,或者,如果使用k = n实际参数表达式调用m并且第k个参数表达式的类型不与T []赋值兼容 ,则参数列表(e1,...,en-1,en,...,ek)被评估为好像被写为(e1,...,en-1,new | T [] | {en,... ,ek}),其中| T [] | denotes the erasure (§4.6) of T[]. 表示T []的擦除(第4.6节)。

(Emphasis mine.) (强调我的。)

The bit I've emphasized is why the wrapping only happens when the compile-time type of the argument is String , not the null type. 我强调的一点是,为什么只有当参数的编译时类型是String而不是null类型时才会发生包装。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM