단일 null 인수를 사용하여 Java varargs 메서드를 호출하시겠습니까?
vararg Java 메서드가 있는 경우foo(Object ...arg)그리고 나는 전화한다.foo(null, null), 둘 다 가지고 있습니다.arg[0]그리고.arg[1]~하듯이nulls. 단, 전화하면foo(null),arg그 자체는 null입니다.왜 이런 일이 생기는 건가요?
어떻게 불러야 하죠?foo그렇게 해서foo.length == 1 && foo[0] == null이true?
문제는 리터럴 null을 사용할 때 Java가 어떤 유형이어야 하는지 모른다는 것입니다.Null Object일 수도 있고 Null Object 배열일 수도 있습니다.단일 논거에 대해서는 후자를 가정한다.
두 가지 선택이 있습니다.null을 Object에 명시적으로 캐스트하거나 strongtype 변수를 사용하여 메서드를 호출합니다.다음의 예를 참조해 주세요.
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가 나타내는 배열 전체로 간주됩니다.
이를 설명하기 위한 테스트 케이스:
varararg-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;
}
}
이 Java 코드(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"
}
}
이를 JUnit 테스트로 실행하면 Java와의 차이가 굵은 글씨로 강조 표시되어 다음과 같은 결과가 나타납니다.
sendNothing(): 수신된 'x'는 크기가 0인 배열입니다.sendNullWithNoCast(): 수신된 'x'가 null입니다.sendNullWithCastToString(): 수신된 'x'가 null입니다.sendNullWithCastToArray(): 수신된 'x'가 null입니다.sendOneValue(): 수신된 'x'는 크기가 1인 배열입니다.sendThreeValues(): 수신된 'x'는 크기가 3인 배열입니다.sendArray(): 수신된 'x'는 크기가 3인 배열입니다.
이는 일련의 배열 요소가 아닌 실제 배열에서 varargs 메서드를 호출할 수 있기 때문입니다.애매모호하게 제공할 때null자체로는 「」를 하고 있습니다.null는 입니다.Object[] :null로로 합니다.Object이 문제를 해결할 수 있습니다.
메서드 오버로드 해결 순서는 (https://docs.oracle.com/javase/specs/jls/se11/html/jls-15.html#jls-15.12.2):
첫 번째 단계에서는 박싱 또는 언박싱 변환 또는 가변 아리티 메서드 호출을 허용하지 않고 과부하 해결을 수행합니다.이 단계에서 적절한 방법을 찾을 수 없는 경우, 처리는 두 번째 단계로 넘어갑니다.
이것에 의해, Java SE 5.0 이전의 Java 프로그래밍 언어에서 유효했던 콜은, 가변 아리티 메서드, 암묵적인 박싱, 및/또는 언박스의 도입의 결과로서 애매한 것으로 간주되지 않는 것이 보증됩니다.단, 변수 아리티법(θ8.4.1)의 선언은 제1단계에서는 변수 아리티법이 고정 아리티법으로 취급되기 때문에 소정의 방법 호출식에 대해 선택된 방법을 변경할 수 있다.예를 들어 m(개체)을 이미 선언한 클래스에서 m(개체...)을 선언하면 m(개체[])이 더 구체적이므로 일부 호출 표현식(예: m(null))에 대해 m(개체)이 더 이상 선택되지 않습니다.
두 번째 단계에서는 박싱 및 언박싱을 허용하면서 과부하 해결을 수행하지만 가변 아리티 메서드 호출의 사용은 여전히 금지됩니다.이 단계에서 적용 가능한 방법이 발견되지 않으면 세 번째 단계로 넘어갑니다.
이렇게 하면 고정 아리티 메서드 호출을 통해 적용할 수 있는 경우 가변 아리티 메서드 호출을 통해 메서드가 선택되지 않습니다.
세 번째 단계에서는 오버로드를 가변 아리티 방식, 박싱 및 언박싱과 조합할 수 있습니다.
foo(null)foo(Object... arg)arg = null【1】arg[0] = null세 번째 단계가 될 거예요. 절대 일어나지 않을 거예요.
나는 더 좋다
foo(new Object[0]);
Null 포인터의 예외를 회피합니다.
도움이 됐으면 좋겠다.
언급URL : https://stackoverflow.com/questions/4028059/calling-java-varargs-method-with-single-null-argument
'source' 카테고리의 다른 글
| MySQL에 있는 테이블 수를 세는 쿼리 (0) | 2022.11.11 |
|---|---|
| SQL 피벗 및 문자열로 저장된 날짜 간의 차이 계산 - MySQL (0) | 2022.11.11 |
| MySQL my.cnf 파일 - 이전 그룹이 없는 옵션을 찾았습니다. (0) | 2022.11.11 |
| 지원되지 않음Instant to String 포맷 시 TemporalTypeException (0) | 2022.11.11 |
| mysqldump 오류: max_allowed_packet'보다 큰 패킷을 받았습니다. (0) | 2022.11.11 |