[java] Java에서 정수 랩퍼를 비교할 때 128 == 128은 거짓이지만 127 == 127은 왜됩니까?

class D {
    public static void main(String args[]) {
        Integer b2=128;
        Integer b3=128;
        System.out.println(b2==b3);
    }
}

산출:

false

class D {
    public static void main(String args[]) {
        Integer b2=127;
        Integer b3=127;
        System.out.println(b2==b3);
    }
}

산출:

true

참고 : -128과 127 사이의 숫자는 true입니다.



답변

Java에서 숫자 리터럴을 컴파일하고이를 정수 (capital I)에 지정하면 컴파일러에서 다음을 생성합니다.

Integer b2 =Integer.valueOf(127)

이 코드 줄은 오토 박싱을 사용할 때도 생성됩니다.

valueOf 특정 숫자가 “풀링”되도록 구현되고 128보다 작은 값에 대해 동일한 인스턴스를 반환합니다.

Java 1.6 소스 코드에서 621 행 :

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

high캔 시스템 특성과 다른 값으로 설정 될 수있다.

-Djava.lang.Integer.IntegerCache.high = 999

해당 시스템 속성으로 프로그램을 실행하면 true로 출력됩니다!

명백한 결론 : 두 개의 참조가 동일하다고 절대 의존하지 말고 항상 .equals()메소드 와 비교하십시오 .

따라서 b2.equals(b3)논리적으로 동일한 모든 b2, b3 값에 대해 true를 인쇄합니다.

Integer캐시는 성능상의 이유가 아니라 JLS 섹션 5.1.7 을 준수 한다는 점에 유의하십시오 . -128에서 127 사이의 값에 대해 개체 ID를 제공해야합니다.

Integer # valueOf (int) 도이 동작을 문서화합니다.

이 방법은 자주 요청되는 값을 캐싱하여 공간 및 시간 성능을 크게 향상시킬 수 있습니다. 이 방법은 항상 -128에서 127 사이의 값을 캐시하며이 범위 밖의 다른 값을 캐시 할 수 있습니다.


답변

오토 박싱은 -128에서 127까지 캐시합니다. 이는 JLS ( 5.1.7 )에 지정되어 있습니다.

박스형 p 가 true, false, 바이트, \ u0000 ~ \ u007f 범위의 문자 또는 -128과 127 사이의 정수 또는 짧은 숫자 인 경우 r1과 r2를 두 개의 권투 변환의 결과로 둡니다. p. 항상 r1 == r2입니다.

객체를 다룰 때 기억해야 할 간단한 규칙 .equals은 두 객체가 “동일한” ==것인지 확인하려는 경우 동일한 인스턴스를 가리키는 지 확인하려는 경우에 사용하는 것입니다.


답변

기본 데이터 유형 인 int를 사용하면 두 경우 모두 예상 출력이 true가됩니다.

그러나 Integer 객체를 사용하고 있기 때문에 == 연산자는 다른 의미를 갖습니다.

객체의 맥락에서 ==는 변수가 동일한 객체 참조를 참조하는지 확인합니다.

객체의 값을 비교하려면 equals () 메소드를 사용해야합니다

 b2.equals(b1)

b2가 b1보다 작거나 크거나 같은지 여부를 나타냅니다 (자세한 내용은 API 확인).


답변

Java 관련 메모리 최적화입니다.

메모리를 절약하기 위해 Java는 값이 다음 범위에 속하는 모든 랩퍼 오브젝트를 ‘재사용’합니다.

모든 부울 값 (true 및 false)

모든 바이트 값

\ u0000에서 \ u007f까지의 모든 문자 값 (예 : 10 진수로 0에서 127)

-128에서 127 사이의 모든 Short 및 Integer 값


답변

값이 -128 ~ 127 사이 인 경우 Integer.java에서보세요, 그렇게, 캐시 풀을 사용 (Integer) 1 == (Integer) 1하는 동안(Integer) 222 != (Integer) 222

 /**
 * Returns an {@code Integer} instance representing the specified
 * {@code int} value.  If a new {@code Integer} instance is not
 * required, this method should generally be used in preference to
 * the constructor {@link #Integer(int)}, as this method is likely
 * to yield significantly better space and time performance by
 * caching frequently requested values.
 *
 * This method will always cache values in the range -128 to 127,
 * inclusive, and may cache other values outside of this range.
 *
 * @param  i an {@code int} value.
 * @return an {@code Integer} instance representing {@code i}.
 * @since  1.5
 */
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);
}       


답변

다른 답변은 관찰 된 효과가 관찰 될 수있는 이유를 설명하지만, 실제로 프로그래머에게는 중요하지 않습니다 (물론 흥미롭지 만 실제 코드를 작성할 때 잊어 버릴 수있는 것).

Integer 객체가 동일한 지 비교하려면이 equals방법을 사용하십시오 .

ID 연산자를 사용하여 Integer 객체가 동일한 지 비교하지 마십시오 ==.

동일한 값이 동일한 객체 일 수도 있지만 일반적으로 의존해야하는 것은 아닙니다.


답변

이 문제는 Integer에만 국한되지 않으므로 다음을 작성했습니다. 내 결론은 API를 잘못 사용하면 틀린 행동을 보게 될 것입니다. 올바르게 사용하면 올바른 동작이 나타납니다.

public static void main (String[] args) {
    Byte b1=127;
    Byte b2=127;

    Short s1=127; //incorrect should use Byte
    Short s2=127; //incorrect should use Byte
    Short s3=128;
    Short s4=128;

    Integer i1=127; //incorrect should use Byte
    Integer i2=127; //incorrect should use Byte
    Integer i3=128;
    Integer i4=128;

    Integer i5=32767; //incorrect should use Short
    Integer i6=32767; //incorrect should use Short

    Long l1=127L;           //incorrect should use Byte
    Long l2=127L;           //incorrect should use Byte
    Long l3=13267L;         //incorrect should use Short
    Long l4=32767L;         //incorrect should use Short
    Long l5=2147483647L;    //incorrect should use Integer 
    Long l6=2147483647L;    //incorrect should use Integer
    Long l7=2147483648L;
    Long l8=2147483648L;

    System.out.print(b1==b2); //true  (incorrect) Used API correctly
    System.out.print(s1==s2); //true  (incorrect) Used API incorrectly
    System.out.print(i1==i2); //true  (incorrect) Used API incorrectly
    System.out.print(l1==l2); //true  (incorrect) Used API incorrectly

    System.out.print(s3==s4); //false (correct) Used API correctly
    System.out.print(i3==i4); //false (correct) Used API correctly
    System.out.print(i5==i6); //false (correct) Used API correctly
    System.out.print(l3==l4); //false (correct) Used API correctly
    System.out.print(l7==l8); //false (correct) Used API correctly
    System.out.print(l5==l6); //false (correct) Used API incorrectly

}