Integer.valueOf (String)과의 == 비교가 왜 127과 128에 대해 다른 결과를 제공합니까?


182

이 코드 줄이 다른 값을 반환하는 이유를 모르겠습니다.

System.out.println(Integer.valueOf("127")==Integer.valueOf("127"));
System.out.println(Integer.valueOf("128")==Integer.valueOf("128"));
System.out.println(Integer.parseInt("128")==Integer.valueOf("128"));

출력은 다음과 같습니다.

true
false
true

첫 번째 것은 왜 돌아가고 true두 번째는 돌아 오는가 false? 127와 사이에 모르는 것이 128있습니까? (물론 나는 그것을 알고 있습니다 127< 128.)

또한 왜 세 번째가 돌아 옵니까 true?

이 질문에 대한 답변 읽었 지만 여전히 어떻게 반환 할 수 있는지 true, 왜 두 번째 줄의 코드 가 반환되는지 알지 못했습니다 false.


6
정수는 객체입니다. 평등을 비교하려면을 사용 .equals()하고 그렇지 않으면 모든 베팅이 해제됩니다.
Karl Damgaard Asmussen

6
@KarlDamgaardAsmussen 사실 여기서는 동일한 객체에 대한 참조인지 테스트하고 싶습니다. 처음에는 127128이 다른 결과를 반환하는 이유를 알 수 없습니다.
DnR

@DnR Java가 표준화 된 사양의 언어라면 구현에 이르기까지 또는 정의되지 않은 동작을 요구한다고 생각합니다.
Karl Damgaard Asmussen

1
@jszumski : 더있어 있지만, 단지 캐싱 부분보다 질문입니다. 게다가, 연결된 답변은 기껏해야 불완전합니다. 캐시 된 내용과 이유에 대해서는 자세히 설명하지 않습니다.
Makoto

1
이 논의에 대한 추가 후속 조치는 이 메타 게시물을 참조하십시오 .
Jeroen Vannevel

답변:


191

여기에는 놀라운 차이가 있습니다.

valueOfInteger-128과 127 사이에 캐시 된 값을 가질 수 있는 객체를 반환합니다 . 이것이 첫 번째 값이 반환되는 이유 true-캐싱 된-두 번째 값이 반환 되는-128이 false캐싱 된 값이 아니기 때문에 두 개의 개별 Integer인스턴스를 얻습니다. .

그것은주의하는 것이 중요하다 당신이 참조를 비교하는 것을 Integer#valueOf, 당신은 무엇을 캐시가 지원하는보다 큰 값을 비교하는 경우, 그것은 것입니다 하지 에 평가 true구문 분석 된 값이 동일하더라도, (적절한 예 : Integer.valueOf(128) == Integer.valueOf(128)). 당신은 해야한다 사용 equals()하는 대신.

parseInt프리미티브를 반환합니다 int. 이 세 번째 값을 반환 왜 true- 128 == 128, 평가, 물론입니다 true.

이제 세 번째 결과를 만드는 데 약간의 어려움이 있습니다 true.

  • 언 박싱 변환이 발생 즉, - 당신이 사용하고있는 등가 연산자와 당신이 가지고있는 데이터 유형에 대한 intInteger. 당신은을 얻고 Integer에서 valueOf물론, 오른쪽에.

  • 변환 후 두 개의 기본 int값을 비교 합니다. 프리미티브와 관련하여 예상 한대로 비교가 이루어 지므로 128와 를 비교할 수 128있습니다.


2
@ user3152527 : 상당한 차이가 있습니다. 하나는 객체로 간주되므로 메소드를 호출하고와 같은 추상 데이터 구조에서 메소드와 상호 작용할 수 있습니다 List. 다른 하나는 기본 값이며 이는 단지 원시 값입니다.
Makoto

1
@ user3152527 훌륭한 질문을했습니다 (최악의 바보 같은 질문은 아님). 그러나 .equals를 사용하도록 수정했습니다.
user2910265

3
아, 질문자가 Java의 기본 사실을 이해하지 못하는 것 같습니다. "=="를 사용하여 두 객체를 비교할 때 동일한 객체에 대한 참조인지 테스트하고 있습니다. "equals ()"를 사용할 때 값이 같은지 테스트하고 있습니다. 프리미티브를 비교하기 위해 "같음"을 사용할 수 없습니다.
Jay

3
@Jay no, 이해합니다. 그러나 처음에 나를 혼동하는 것은 첫 번째 것이 동일한 비교 방법을 사용하여 true를 반환하고 두 번째가 false를 반환하는 이유 ==입니다. 어쨌든 지금은 분명합니다.
DnR

1
Nit : Integer가 -128과 127 사이에 캐시 될 수있는 것은 아닙니다 . JLS 5.1.7따라야합니다 . 그것은 그 범위의 외부 캐시 할 수 있지만 필요는 없습니다 (자주하지 않습니다).
yshavit

127

Integer클래스에는 Integer-128에서 127 사이의 모든 값에 대해 하나씩 256 개의 특수 객체 를 저장하는 정적 캐시가 있습니다 .이를 염두에두고이 세 가지의 차이점을 고려하십시오.

new Integer(123);

이것은 (분명히) 아주 새로운 Integer대상을 만듭니다.

Integer.parseInt("123");

int구문 분석 후 프리미티브 값을 반환 합니다 String.

Integer.valueOf("123");

이것은 다른 것보다 더 복잡합니다. 를 파싱하여 시작합니다 String. 그런 다음 값이 -128과 127 사이이면 정적 캐시에서 해당 객체를 반환합니다. 값이이 범위를 벗어나면 값을 호출 new Integer()하고 전달하여 새 객체를 얻습니다.

이제 질문의 세 가지 표현을 고려하십시오.

Integer.valueOf("127")==Integer.valueOf("127");

Integer값이 127 인 정적 캐시에서 두 번 검색되어 자체 비교 되기 때문에 true를 리턴합니다 . Integer관련된 객체는 하나뿐 이므로이를 반환합니다 true.

Integer.valueOf("128")==Integer.valueOf("128");

false128은 정적 캐시에 없으므로을 반환 합니다. 따라서 Integer평등의 각 측면에 대해 새로운 것이 만들어집니다. 두 개의 다른 Integer객체가 있고 양쪽이 정확히 동일한 객체 인 경우 ==에만 객체를 반환 true하므로이 값은 false입니다.

Integer.parseInt("128")==Integer.valueOf("128");

int왼쪽 의 프리미티브 값 128과 Integer오른쪽 의 새로 생성 된 객체를 비교합니다. 그것이 비교하는 것은 의미가 없기 때문에 그러나 int에를 Integer, 자바는 자동 - 언 박싱 것 Integer비교를하기 전에; 그래서 당신은과 비교 int합니다 int. 프리미티브 (128)는 그 자체와 같기 때문에을 리턴한다 true.


13

이 메소드에서 값을 리턴하도록주의하십시오. 위해 valueOf 메소드는 정수 인스턴스를 반환합니다 :

public static Integer valueOf(int i)

으로 parseInt의 값 (기본 타입)에있어서의 정수를 반환 :

public static int parseInt(String s) throws NumberFormatException

비교 설명 :

메모리를 절약하기 위해 래퍼 객체의 두 인스턴스는 기본 값이 같을 때 항상 ==입니다.

  • 부울
  • 바이트
  • \ u0000에서 \ u007f까지의 문자 (7f는 10 진수로 127입니다)
  • -128에서 127 사이의 짧은 정수

==를 사용하여 기본 요소와 랩퍼를 비교하면 랩퍼가 랩핑되지 않고 비교가 기본 요소와 기본 요소가됩니다.

귀하의 상황에서 (위의 규칙에 따라) :

Integer.valueOf("127")==Integer.valueOf("127")

이 표현식은 -128에서 127 사이의 Integer 값을 포함하므로 동일한 객체에 대한 참조를 비교하여 반환합니다 true.

Integer.valueOf("128")==Integer.valueOf("128")

이 표현식은 <-128, 127>에없는 Integer 값을 포함하므로 다른 객체에 대한 참조를 비교하므로이를 반환합니다 false.

Integer.parseInt("128")==Integer.valueOf("128")

이 표현식은 프리미티브 값 (왼쪽)과 객체 (오른쪽)에 대한 참조를 비교하여 오른손이 풀리고 그의 프리미티브 유형이 왼쪽과 비교되어 반환 true됩니다.



견적 소스에 대한 URL을 제공 할 수 있습니까?
Philzen

"... 래퍼 객체의 두 인스턴스는 기본 값이 같을 때 항상 ==입니다 ..." -절대적으로 거짓. 동일한 값을 가진 두 개의 랩퍼 오브젝트를 작성하면 ==서로 다른 오브젝트이므로 와 비교할 때 true를 리턴하지 않습니다 .
다우드 이븐 카림

6

정수 오브젝트는 256 정수의 -128-127 사이에서 캐시합니다.

객체 참조를 == 또는 ! = 와 비교해서는 안됩니다 . 을 사용해야합니다. 대신 equals (..) 또는 더 나은-정수 대신 기본 int를 사용하십시오.

parseInt : 문자열 인수를 부호있는 10 진수 정수로 구문 분석합니다. 문자열의 문자는 모두 10 진수 여야합니다. 첫 번째 문자는 음수 값을 나타내는 ASCII 빼기 기호 '-'( '\ u002D') 일 수 있습니다. 인수와 기수 10이 parseInt (java.lang.String, int) 메소드에 인수로 제공된 것처럼 결과 정수 값이 리턴됩니다.

valueOf 두 번째 인수로 주어진 기수로 구문 분석 될 때 지정된 문자열에서 추출 된 값을 보유하는 Integer 오브젝트를 리턴합니다. 첫 번째 인수는 마치 인수가 parseInt (java.lang.String, int) 메소드에 제공된 것처럼 두 번째 인수로 지정된 기수의 부호있는 정수를 나타내는 것으로 해석됩니다. 결과는 문자열로 지정된 정수 값을 나타내는 Integer 객체입니다.

에 해당

new Integer(Integer.parseInt(s, radix))

기수-s 해석에 사용되는 기수

따라서 Integer.valueOf()사이의 정수와 같으면

-128 ~ 127 조건에 따라 true를 반환합니다.

대한 lesser than-128과 greater than127이 제공false


6

주어진 답변을 보완하려면 다음 사항에 유의하십시오.

public class Test { 
    public static void main(String... args) { 
        Integer a = new Integer(129);
        Integer b = new Integer(129);
        System.out.println(a == b);
    }
}

이 코드는 다음과 같이 인쇄됩니다. false

Jay 사용자 가 허용 된 답변에 대한 의견에서 주장 했듯이 ==객체에 연산자 를 사용할 때주의를 기울여야합니다 . 여기서 두 참조가 서로 다르기 때문에 두 참조가 동일한 지 여부를 확인하고 있습니다. 같은 가치. 객체를 비교하려면 equals 대신 메소드를 사용해야합니다 .

Integer a = new Integer(128);
Integer b = new Integer(128);
System.out.println(a.equals(b));

인쇄됩니다 : true

당신은 물어 수 있습니다 첫 번째 줄이 인쇄 된 이유를 다음 그러나 true? . Integer.valueOf메소드 의 소스 코드를 확인하면 다음을 볼 수 있습니다.

public static Integer valueOf(String s) throws NumberFormatException {
    return Integer.valueOf(parseInt(s, 10));
}

public static Integer valueOf(int i) {
    assert IntegerCache.high >= 127;
    if (i >= IntegerCache.low && i <= IntegerCache.high)
        return IntegerCache.cache[i + (-IntegerCache.low)];
    return new Integer(i);
}

param이 IntegerCache.low(기본값은 -128)과 IntegerCache.high(런타임에서 최소값 127로 계산 된 ) 사이의 정수 이면 사전 할당 된 (캐시 된) 객체가 반환됩니다. 따라서 127을 매개 변수로 사용하면 동일한 캐시 된 객체에 대한 두 개의 참조를 얻고 참조를 true비교하게됩니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.