단일 null 인수로 Java varargs 메서드를 호출합니까?
나는 가변 인자 자바 방법이 있다면 foo(Object ...arg)
내가 전화를 foo(null, null)
, 나는 모두가 arg[0]
와 arg[1]
로 null
들. 그러나 내가 호출 foo(null)
하면 arg
자체가 null입니다. 왜 이런 일이 발생합니까?
어떻게 호출해야 foo
그러한 foo.length == 1 && foo[0] == null
입니다 true
?
문제는 리터럴 null을 사용할 때 Java가 어떤 유형인지 알지 못한다는 것입니다. null Object이거나 null Object 배열 일 수 있습니다. 단일 인수의 경우 후자를 가정합니다.
두 가지 선택이 있습니다. null을 명시 적으로 Object로 캐스팅하거나 강력한 형식의 변수를 사용하여 메서드를 호출합니다. 아래 예를 참조하십시오.
public class Temp{
public static void main(String[] args){
foo("a", "b", "c");
foo(null, null);
foo((Object)null);
Object bar = null;
foo(bar);
}
private static void foo(Object...args) {
System.out.println("foo called, args: " + asList(args));
}
}
산출:
foo called, args: [a, b, c]
foo called, args: [null, null]
foo called, args: [null]
foo called, args: [null]
다음에 대한 명시 적 캐스트가 필요합니다 Object
.
foo((Object) null);
그렇지 않으면 인수는 varargs가 나타내는 전체 배열로 간주됩니다.
이를 설명하는 테스트 케이스 :
vararg-taking 메소드 선언이있는 Java 코드 (정적 임) :
public class JavaReceiver {
public static String receive(String... x) {
String res = ((x == null) ? "null" : ("an array of size " + x.length));
return "received 'x' is " + res;
}
}
이 자바 코드 (JUnit4 테스트 케이스)는 위의 코드를 호출합니다 (테스트 케이스를 사용하여 아무것도 테스트하지 않고 출력을 생성합니다).
import org.junit.Test;
public class JavaSender {
@Test
public void sendNothing() {
System.out.println("sendNothing(): " + JavaReceiver.receive());
}
@Test
public void sendNullWithNoCast() {
System.out.println("sendNullWithNoCast(): " + JavaReceiver.receive(null));
}
@Test
public void sendNullWithCastToString() {
System.out.println("sendNullWithCastToString(): " + JavaReceiver.receive((String)null));
}
@Test
public void sendNullWithCastToArray() {
System.out.println("sendNullWithCastToArray(): " + JavaReceiver.receive((String[])null));
}
@Test
public void sendOneValue() {
System.out.println("sendOneValue(): " + JavaReceiver.receive("a"));
}
@Test
public void sendThreeValues() {
System.out.println("sendThreeValues(): " + JavaReceiver.receive("a", "b", "c"));
}
@Test
public void sendArray() {
System.out.println("sendArray(): " + JavaReceiver.receive(new String[]{"a", "b", "c"}));
}
}
이것을 JUnit 테스트로 실행하면 다음이 생성됩니다.
sendNothing () : 수신 된 'x'는 크기 0의 배열입니다. sendNullWithNoCast () : 수신 된 'x'가 null입니다. sendNullWithCastToString () : 수신 된 'x'는 크기 1의 배열입니다. sendNullWithCastToArray () : 수신 된 'x'가 null입니다. sendOneValue () : 수신 된 'x'는 크기 1의 배열입니다. sendThreeValues () : 수신 된 'x'는 크기 3의 배열입니다. sendArray () : 수신 된 'x'는 크기 3의 배열입니다.
이를 더 흥미롭게 만들기 위해 receive()
Groovy 2.1.2 에서 함수를 호출하고 어떤 일이 발생하는지 살펴 보겠습니다 . 결과가 같지 않다는 것이 밝혀졌습니다! 하지만 이것은 버그 일 수 있습니다.
import org.junit.Test
class GroovySender {
@Test
void sendNothing() {
System.out << "sendNothing(): " << JavaReceiver.receive() << "\n"
}
@Test
void sendNullWithNoCast() {
System.out << "sendNullWithNoCast(): " << JavaReceiver.receive(null) << "\n"
}
@Test
void sendNullWithCastToString() {
System.out << "sendNullWithCastToString(): " << JavaReceiver.receive((String)null) << "\n"
}
@Test
void sendNullWithCastToArray() {
System.out << "sendNullWithCastToArray(): " << JavaReceiver.receive((String[])null) << "\n"
}
@Test
void sendOneValue() {
System.out << "sendOneValue(): " + JavaReceiver.receive("a") << "\n"
}
@Test
void sendThreeValues() {
System.out << "sendThreeValues(): " + JavaReceiver.receive("a", "b", "c") << "\n"
}
@Test
void sendArray() {
System.out << "sendArray(): " + JavaReceiver.receive( ["a", "b", "c"] as String[] ) << "\n"
}
}
Running this as a JUnit test yields the following, with the difference to Java highlighted in bold.
sendNothing(): received 'x' is an array of size 0 sendNullWithNoCast(): received 'x' is null sendNullWithCastToString(): received 'x' is null sendNullWithCastToArray(): received 'x' is null sendOneValue(): received 'x' is an array of size 1 sendThreeValues(): received 'x' is an array of size 3 sendArray(): received 'x' is an array of size 3
This is because a varargs method can be called with an actual array rather than a series of array elements. When you provide it with the ambiguous null
by itself, it assumes the null
is an Object[]
. Casting the null
to Object
will fix this.
I prefer
foo(new Object[0]);
to avoid Null pointer exceptions.
Hope it helps.
The ordering for method overloading resolution is (https://docs.oracle.com/javase/specs/jls/se11/html/jls-15.html#jls-15.12.2):
The first phase performs overload resolution without permitting boxing or unboxing conversion, or the use of variable arity method invocation. If no applicable method is found during this phase then processing continues to the second phase.
This guarantees that any calls that were valid in the Java programming language before Java SE 5.0 are not considered ambiguous as the result of the introduction of variable arity methods, implicit boxing and/or unboxing. However, the declaration of a variable arity method (§8.4.1) can change the method chosen for a given method method invocation expression, because a variable arity method is treated as a fixed arity method in the first phase. For example, declaring m(Object...) in a class which already declares m(Object) causes m(Object) to no longer be chosen for some invocation expressions (such as m(null)), as m(Object[]) is more specific.
The second phase performs overload resolution while allowing boxing and unboxing, but still precludes the use of variable arity method invocation. If no applicable method is found during this phase then processing continues to the third phase.
This ensures that a method is never chosen through variable arity method invocation if it is applicable through fixed arity method invocation.
The third phase allows overloading to be combined with variable arity methods, boxing, and unboxing.
foo(null)
matches foo(Object... arg)
with arg = null
in the first phase. arg[0] = null
would be the third phase, which never happens.
참고URL : https://stackoverflow.com/questions/4028059/calling-java-varargs-method-with-single-null-argument
'IT박스' 카테고리의 다른 글
신뢰할 수있는 UDP가 필요할 때 무엇을 사용합니까? (0) | 2020.09.08 |
---|---|
테이블의 열을 논리적으로 재정렬 할 수 있습니까? (0) | 2020.09.08 |
Lisp-1과 Lisp-2의 차이점은 무엇입니까? (0) | 2020.09.08 |
REST API : 사용자 지정 HTTP 헤더와 URL 매개 변수 (0) | 2020.09.08 |
Docker에서 종속 자식 이미지 목록을 가져 오는 방법은 무엇입니까? (0) | 2020.09.08 |