다음 스 니펫에서 간단한 Java 코드를 살펴 보겠습니다.
public class Main {
private int temp() {
return true ? null : 0;
// No compiler error - the compiler allows a return value of null
// in a method signature that returns an int.
}
private int same() {
if (true) {
return null;
// The same is not possible with if,
// and causes a compile-time error - incompatible types.
} else {
return 0;
}
}
public static void main(String[] args) {
Main m = new Main();
System.out.println(m.temp());
System.out.println(m.same());
}
}
이 가장 간단한 Java 코드 temp()
에서 함수의 리턴 유형이이지만 메소드는 컴파일러 오류를 발행하지 않으며 (문을 통해 ) int
값을 리턴하려고합니다 . 컴파일되면 런타임 예외가 발생 합니다.null
return true ? null : 0;
NullPointerException
그러나 if
( same()
메소드 에서 와 같이) 명령문으로 삼항 연산자를 나타내면 컴파일 타임 오류 가 발생하는 경우에도 같은 문제가 발생합니다! 왜?
답변
컴파일러는 null
에 대한 null 참조로 해석 Integer
하고 조건부 연산자 ( Java Language Specification, 15.25에 설명 된대로)에 대한 오토 박싱 / 언 박싱 규칙을 적용하고 행복하게 진행합니다. NullPointerException
런타임시 이를 생성하여 시도하여 확인할 수 있습니다.
답변
Java 컴파일러 true ? null : 0
는 Integer
표현식으로 해석 되며 암시 적으로로 변환 int
하여을 제공 할 수 있다고 생각합니다 NullPointerException
.
두 번째 경우를 들어, 표현은 null
특별하다 널 유형 참조 코드가 있으므로, return null
형식이 일치한다.
답변
실제로, 그 모든 것은 Java 언어 사양에 설명되어 있습니다.
조건식의 유형은 다음과 같이 결정됩니다.
- 두 번째 및 세 번째 피연산자가 동일한 유형 (널 유형일 수 있음)을 갖는 경우 이는 조건식의 유형입니다.
따라서 귀하의 “null” (true ? null : 0)
은 int 유형을 얻은 다음 정수로 자동 박스됩니다.
이것을 확인하기 위해 이와 같은 것을 시도 (true ? null : null)
하면 컴파일러 오류가 발생합니다.
답변
if
명령문 의 경우 null
참조는 Integer
참조 로 해석되도록 하는 표현식에 참여하지 않으므로 참조 로 취급 되지 않습니다 . 따라서 오류가 더 명확하게 유형 오류 이므로 컴파일 타임에 오류가 쉽게 잡힐 수 있습니다 .
조건부 연산자와 관련하여 Java 언어 사양 §15.25“조건부 연산자 ? :
”는 유형 변환이 적용되는 규칙에 따라 다음과 같이 잘 응답합니다.
- 두 번째 및 세 번째 피연산자가 동일한 유형 (널 유형일 수 있음)을 갖는 경우 이는 조건식의 유형입니다.
이 없기 때문에 적용
null
되지 않습니다int
.
- 두 번째 및 세 번째 피연산자 중 하나가 부울 유형이고 다른 유형의 부울이 유형이 부울 인 경우 조건식의 유형은 부울입니다.
어느 쪽도 있기 때문에 적용되지 않음
null
도int
없다boolean
나Boolean
.
- 두 번째 및 세 번째 피연산자 중 하나가 널 유형이고 다른 유형의 유형이 참조 유형 인 경우 조건식의 유형은 해당 참조 유형입니다. 널 유형
이므로 적용 되지 않지만 참조 유형은 아닙니다.
null
int
- 그렇지 않으면 두 번째 및 세 번째 피연산자에 숫자 유형으로 변환 가능한 유형 (§5.1.8)이있는 경우 몇 가지 경우가 있습니다. […]
적용 :
null
숫자 유형으로 변환 가능한 것으로 취급되며 §5.1에 정의되어 있습니다. 8“Unboxing Conversion”을 던지십시오NullPointerException
.
답변
가장 먼저 염두에 두어야 할 것은 Java 3 진 연산자에는 “유형”이 있으며 이는 두 번째 또는 세 번째 매개 변수의 실제 / 실제 유형에 관계없이 컴파일러가 결정하고 고려하는 것입니다. 몇 가지 요인에 따라 삼항 연산자 유형은 Java 언어 사양 15.26에 설명 된대로 다른 방식으로 결정됩니다.
위의 질문에서 우리는 마지막 경우를 고려해야합니다.
그렇지 않으면, 두 번째 및 세 번째 피연산자는 각각 S1 및 S2 유형 입니다. 하자 T1이 에 권투 변환을 적용 결과 그 유형이 될 S1 및하자가 T2 타입이 될 그에게 권투 변환을 적용 결과 S2 . 조건식의 유형은 캡처 변환 (§5.1.10)을 lub (T1, T2) (§15.12.2.7) 에 적용한 결과입니다 .
캡처 변환 (§5.1.10) 적용을 살펴보면 가장 복잡한 경우 입니다. lub (T1, T2)입니다.
평범한 영어로 그리고 극단적으로 단순화 한 후에 프로세스는 두 번째 및 세 번째 매개 변수의 “최소 공통 수퍼 클래스”(예, LCM 생각)를 계산하는 것으로 설명 할 수 있습니다. 이것은 삼항 연산자 “type”을 줄 것입니다. 다시 말하지만 방금 말한 것은 극단적 인 단순화입니다 (여러 공통 인터페이스를 구현하는 클래스 고려).
예를 들어 다음을 시도하면
long millis = System.currentTimeMillis();
return(true ? new java.sql.Timestamp(millis) : new java.sql.Time(millis));
조건식의 결과 유형은 /에 java.util.Date
대한 “최소 공통 수퍼 클래스”이므로Timestamp
Time
쌍 .
null
무엇이든 오토 박스 할 수 있기 때문에 “최소 공통 수퍼 클래스”는Integer
클래스이며 위의 조건식 (삼항 연산자)의 반환 유형이됩니다. 리턴 값은 유형의 널 포인터가 Integer
되고 이는 삼항 연산자에 의해 리턴됩니다.
런타임에 Java Virtual Machine이 개봉하면 Integer
a NullPointerException
가 발생합니다. JVM이 함수를 호출하려고하기 때문에 발생합니다 null.intValue()
.null
autoboxing의 결과입니다.
내 의견으로는 (그리고 내 의견은 Java 언어 사양에 없기 때문에 많은 사람들이 어쨌든 잘못 알 것입니다) 컴파일러는 귀하의 질문에 표현을 평가하는 데 열악한 일을합니다. true ? param1 : param2
컴파일러가 작성한 것을 고려 하면 첫 번째 매개 변수– null
가 반환되고 컴파일러 오류가 발생 하는지 즉시 결정 해야합니다. 이것은 작성시 while(true){} etc...
와 다소 유사 하며 컴파일러는 루프 아래의 코드에 대해 불평하고로 플래그를 지정합니다 Unreachable Statements
.
두 번째 경우는 매우 간단 하며이 답변은 이미 너무 깁니다 …;)
보정:
다른 분석 후 나는 null
가치가 무엇이든 박스 / 오토 박스 될 수 있다고 말하는 것이 잘못되었다고 생각합니다 . 클래스 Integer에 대해 말하면, 명시 적 권투는 new Integer(...)
생성자 또는 Integer.valueOf(int i);
(어딘가 에서이 버전을 찾았 습니다)를 호출하는 것으로 구성 됩니다. 전자는 NumberFormatException
(그리고 이것이 일어나지 않습니다) 던지는 반면 두 번째는 불가능하기 때문에 의미 int
가 없습니다 null
…
답변
실제로 첫 번째 경우에는 컴파일러가 알고 있으므로 식을 평가할 수 Integer
있지만 두 번째 경우에는 반환 값 ( null
) 의 유형을 결정할 수 없으므로 컴파일 할 수 없습니다. 로 캐스팅 Integer
하면 코드가 컴파일됩니다.
답변
private int temp() {
if (true) {
Integer x = null;
return x;// since that is fine because of unboxing then the returned value could be null
//in other words I can say x could be null or new Integer(intValue) or a intValue
}
return (true ? null : 0); //this will be prefectly legal null would be refrence to Integer. The concept is one the returned
//value can be Integer
// then null is accepted to be a variable (-refrence variable-) of Integer
}