이 상황을 관찰하는 것은 매우 혼란 스럽습니다.
Integer i = null;
String str = null;
if (i == null) { //Nothing happens
...
}
if (str == null) { //Nothing happens
}
if (i == 0) { //NullPointerException
...
}
if (str == "0") { //Nothing happens
...
}
따라서 권투 작업이 먼저 실행되고 (즉, java가에서 int 값을 추출하려고 시도 함 null
) 비교 작업의 우선 순위가 낮기 때문에 예외가 발생합니다.
문제는 왜 Java에서 이런 방식으로 구현됩니까? 권투가 참조 비교보다 우선 순위가 높은 이유는 무엇입니까? 아니면 왜 null
복싱 전에 검증을 구현하지 않았 습니까?
현재는 NullPointerException
래핑 된 프리미티브와 함께 던져지고 진정한 객체 유형으로 던져지지 않을 때 일관성 이 없어 보입니다 .
답변
짧은 답변
요점은 다음과 같습니다.
==
두 참조 유형 간에는 항상 참조 비교입니다.- 자주 사용하지 않는 경우 (예 :
Integer
및String
)equals
대신 사용하는 것이 좋습니다.
- 자주 사용하지 않는 경우 (예 :
==
참조 유형과 숫자 기본 유형 사이는 항상 숫자 비교입니다.- 참조 유형은 unboxing 변환의 대상이됩니다.
- 개봉기는
null
항상 던집니다NullPointerException
- Java에는에 대한 많은 특수 처리가 있지만
String
실제로는 기본 유형이 아닙니다.
위의 문은 주어진 유효한 Java 코드를 유지합니다. 이러한 이해를 바탕으로 귀하가 제시 한 스 니펫에 어떤 불일치도 없습니다.
긴 답변
다음은 관련 JLS 섹션입니다.
JLS 15.21.3 참조 같음 연산자
==
및!=
같음 연산자의 피연산자가 모두 참조 유형이거나 널 유형이면 연산은 객체 같음입니다.
이것은 다음을 설명합니다.
Integer i = null;
String str = null;
if (i == null) { // Nothing happens
}
if (str == null) { // Nothing happens
}
if (str == "0") { // Nothing happens
}
두 피연산자는 모두 참조 유형 ==
이므로 참조 동일성 비교입니다.
이것은 또한 다음을 설명합니다.
System.out.println(new Integer(0) == new Integer(0)); // "false"
System.out.println("X" == "x".toUpperCase()); // "false"
들어 ==
숫자 평등으로, 피연산자 중 적어도 하나는 숫자 유형이어야합니다 :
JLS 15.21.1 숫자 평등 연산자
==
및!=
항등 연산자의 피연산자가 모두 숫자 유형이거나 하나가 숫자 유형이고 다른 하나가 숫자 유형 으로 변환 가능한 경우 피연산자에 대해 2 진 숫자 승격이 수행됩니다. 승격 된 피연산자의 유형이
int
또는long
인 경우 정수 동등성 테스트가 수행됩니다. 승격 된 유형이float or
double`이면 부동 소수점 동등성 테스트가 수행됩니다.이진 숫자 승격은 값 세트 변환 및 개봉 변환을 수행합니다.
이것은 다음을 설명합니다.
Integer i = null;
if (i == 0) { //NullPointerException
}
다음은 Effective Java 2nd Edition, 항목 49 에서 발췌 한 것입니다 . 박스형 기본 형식보다 기본 형식을 선호합니다 .
요약하면, 선택할 수있을 때마다 boxed primitive보다 우선적으로 primitive를 사용하십시오. 기본 유형은 더 간단하고 빠릅니다. 박스형 프리미티브를 사용해야한다면 조심하세요! Autoboxing은 boxed primitives를 사용하는 위험은 아니지만 자세한 정도를 줄입니다. 프로그램이 두 개의 박스형 프리미티브를
==
연산자 와 비교할 때 ID 비교를 수행합니다. 이는 거의 확실히 원하는 것이 아닙니다. 프로그램이 boxed 및 unboxed 프리미티브와 관련된 혼합 유형 계산을 수행하면 unboxing을 수행하고 프로그램이 unboxing을 수행하면NullPointerException
. 마지막으로, 프로그램이 기본 값을 상자에 넣으면 비용이 많이 들고 불필요한 객체 생성이 발생할 수 있습니다.
제네릭과 같은 boxed primitive를 사용하는 것 외에 선택의 여지가없는 곳이 있습니다. 그렇지 않으면 boxed primitive를 사용하기로 한 결정이 정당한지 진지하게 고려해야합니다.
참고 문헌
- JLS 4.2. 기본 유형 및 값
- ” 숫자 유형 은 정수 유형과 부동 소수점 유형입니다.”
- JLS 5.1.8 언 박싱 변환
- “유형은 숫자 유형 인 경우 숫자 유형으로 변환 할 수 있거나 unboxing 변환을 통해 숫자 유형으로 변환 할 수있는 참조 유형입니다.”
- “Unboxing 변환은 […]을 유형에서 유형
Integer
으로 변환 합니다.int
“ - “경우
r
입니다null
, 언 박싱 변환이 발생NullPointerException
“
- 자바 언어 가이드 / 오토 박싱
- JLS 15.21.1 숫자 평등 연산자
==
및!=
- JLS 15.21.3 참조 같음 연산자
==
및!=
- JLS 5.6.2 이진 숫자 승격
관련 질문
관련 질문
- Java / C #에서 int와 Integer의 차이점은 무엇입니까?
- Java에서 new Integer (i) == i가 보장됩니까? (예 !!! 상자가 개봉되어 있습니다. 다른 방법이 아닙니다!)
- 왜
int num = Integer.getInteger("123")
던지NullPointerException
나요? (!!!) - Java noob : 객체에 대한 제네릭 만? (안타깝게도, 맞아)
- 자바
String.equals
대==
답변
NPE 예제는 autoboxing 덕분에이 코드와 동일합니다 .
if ( i.intValue( ) == 0 )
따라서 NPE i
가 null
.
답변
if (i == 0) { //NullPointerException
...
}
나는 정수이고 0은 정수이므로 실제로 수행되는 작업은 다음과 같습니다.
i.intValue() == 0
그리고 i가 null이기 때문에 nullPointer가 발생합니다. String의 경우이 작업이 없으므로 예외가 없습니다.
답변
자바의 업체가 정의한 수있는 ==
경우가 부여하는 직접 다른 유형의 피연산자에 따라 행동하는 연산자, Integer I; int i;
비교 I==i;
질문을 수 “를합니까는 I
에 대한 참조를 개최 Integer
, 그 값을 i
?”- 어려움없이 대답 할 수있는 질문을 I
null 인 경우에도 . 불행히도 Java는 다른 유형의 피연산자가 같은지 직접 확인하지 않습니다. 대신 언어가 두 피연산자의 유형을 다른 유형으로 변환 할 수 있는지 확인하고 변환 된 피연산자를 변환되지 않은 피연산자와 비교합니다. 변수 그러한 행동 수단 x
, y
및 z
유형의 몇 가지 조합으로, 그것을 가지고하는 것이 가능 x==y
하고 y==z
있지만,x!=z
[예 : x = 16777216f y = 16777216 z = 16777217]. 또한 비교 I==i
가 “I를로 변환 int
하고 예외가 발생하지 않으면. “로 변환 됨을 의미합니다 i
.
답변
Javas autoboxing 기능 때문입니다 . 컴파일러는 비교의 오른쪽에서 기본 정수를 사용하고 있으며 래퍼 정수 값을 기본 정수 값으로 분리해야 함을 감지합니다.
그것은 가능하지 않기 때문에 (줄을 긋은 것처럼 null NullPointerException
입니다) 던졌습니다.
답변
i == 0
Java 에서는 자동 언 박싱을 시도하고 수치 비교를 수행합니다 (예 : “값 i
과 동일하게 참조되는 래퍼 객체에 저장된 값 0
입니까?”).
이후 i
입니다 null
언 박싱이 발생합니다 NullPointerException
.
추론은 다음과 같습니다.
JLS § 15.21.1 Numerical Equality Operators == 및! = 의 첫 번째 문장은 다음과 같이 읽습니다.
등호 연산자의 피연산자가 모두 숫자 유형이거나 하나는 숫자 유형이고 다른 하나는 숫자 유형으로 변환 가능한 (§5.1.8) 피연산자에 대해 이진 숫자 승격이 수행됩니다 (§5.6.2).
분명히 i
숫자 유형으로 변환 가능하고 숫자 유형 0
이므로 이진 숫자 승격이 피연산자에서 수행됩니다.
§ 5.6.2 이진 숫자 프로모션 은 다음과 같이 말합니다.
피연산자 중 하나라도 참조 유형이면 unboxing 변환 (§5.1.8)이 수행됩니다.
§ 5.1.8 Unboxing Conversion 은 다음과 같이 말합니다.
경우 , R은 널 (null)이, 언 박싱 변환은 던졌습니다
NullPointerException
답변
단순히 메서드를 작성하고 호출하여 NullPointerException을 피하십시오.
public static Integer getNotNullIntValue(Integer value)
{
if(value!=null)
{
return value;
}
return 0;
}