Integer와 int를 비교하면 Java에서 NullPointerException이 발생할 수있는 이유는 무엇입니까?
이 상황을 관찰하는 것은 매우 혼란 스럽습니다.
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 에서 발췌 한 것입니다 . 박스형 기본 형식보다 기본 형식을 선호합니다 .
In summary, use primitives in preference to boxed primitive whenever you have the choice. Primitive types are simpler and faster. If you must use boxed primitives, be careful! Autoboxing reduces the verbosity, but not the danger, of using boxed primitives. When your program compares two boxed primitives with the
==
operator, it does an identity comparison, which is almost certainly not what you want. When your program does mixed-type computations involving boxed and unboxed primitives, it does unboxing, and when your program does unboxing, it can throwNullPointerException
. Finally, when your program boxes primitive values, it can result in costly and unnecessary object creations.
There are places where you have no choice but to use boxed primitives, e.g. generics, but otherwise you should seriously consider if a decision to use boxed primitives is justified.
References
- JLS 4.2. Primitive Types and Values
- "The numeric types are the integral types and the floating-point types."
- JLS 5.1.8 Unboxing Conversion
- "A type is said to be convertible to a numeric type if it is a numeric type, or it is a reference type that may be converted to a numeric type by unboxing conversion."
- "Unboxing conversion converts [...] from type
Integer
to typeint
" - "If
r
isnull
, unboxing conversion throws aNullPointerException
"
- Java Language Guide/Autoboxing
- JLS 15.21.1 Numerical Equality Operators
==
and!=
- JLS 15.21.3 Reference Equality Operators
==
and!=
- JLS 5.6.2 Binary Numeric Promotion
Related questions
- When comparing two
Integers
in Java does auto-unboxing occur? - Why are these
==
but notequals()
? - Java: What’s the difference between autoboxing and casting?
Related questions
- What is the difference between an int and an Integer in Java/C#?
- Is it guaranteed that new Integer(i) == i in Java? (YES!!! The box is unboxed, not other way around!)
- Why does
int num = Integer.getInteger("123")
throwNullPointerException
? (!!!) - Java noob: generics over objects only? (yes, unfortunately)
- Java
String.equals
versus==
Your NPE example is equivalent to this code, thanks to autoboxing:
if ( i.intValue( ) == 0 )
Hence NPE if i
is null
.
The makers of Java could have defined the ==
operator to directly act upon operands of different types, in which case given Integer I; int i;
the comparison I==i;
could ask the question "Does I
hold a reference to an Integer
whose value is i
?"--a question which could be answered without difficulty even when I
is null. Unfortunately, Java does not directly check whether operands of different types are equal; instead, it checks whether the language allows the type of either operand to be converted to the type of the other and--if it does--compares the converted operand to the non-converted one. Such behavior means that for variables x
, y
, and z
with some combinations of types, it's possible to have x==y
and y==z
but x!=z
[e.g. x=16777216f y=16777216 z=16777217]. It also means that the comparison I==i
is translated as "Convert I to an int
and, if that doesn't throw an exception, compare it to i
."
if (i == 0) { //NullPointerException
...
}
i is an Integer and the 0 is an int so in the what really is done is something like this
i.intValue() == 0
And this cause the nullPointer because the i is null. For String we do not have this operation, thats why is no exception there.
It's because of Javas autoboxing feature. The compiler detects, that on the right hand side of the comparison you're using a primitive integer and needs to unbox the wrapper Integer value into a primitive int value as well.
Since that's not possible (it's null as you lined out) the NullPointerException
is thrown.
In i == 0
Java will try to do auto-unboxing and do a numerical comparison (i.e. "is the value stored in the wrapper object referenced by i
the same as the value 0
?").
Since i
is null
the unboxing will throw a NullPointerException
.
The reasoning goes like this:
The first sentence of JLS § 15.21.1 Numerical Equality Operators == and != reads like this:
If the operands of an equality operator are both of numeric type, or one is of numeric type and the other is convertible (§5.1.8) to numeric type, binary numeric promotion is performed on the operands (§5.6.2).
Clearly i
is convertible to a numeric type and 0
is a numeric type, so the binary numeric promotion is performed on the operands.
§ 5.6.2 Binary Numeric Promotion says (among other things):
If any of the operands is of a reference type, unboxing conversion (§5.1.8) is performed.
§ 5.1.8 Unboxing Conversion says (among other things):
If r is null, unboxing conversion throws a
NullPointerException
'program story' 카테고리의 다른 글
Node.js 및 AngularJS 애플리케이션 구조화 (0) | 2020.10.15 |
---|---|
클래스 경로 리소스 (XML 파일)에서 입력 스트림 가져 오기 (0) | 2020.10.14 |
MySQL : SQL 쿼리의 각 결과에 대한 레코드를 삽입하는 방법은 무엇입니까? (0) | 2020.10.14 |
PHP-클래스 내부에 상수 정의 (0) | 2020.10.14 |
로컬 mongo db를 시작 / 실행할 수 없습니다. (0) | 2020.10.14 |