[java] 자바의 이상한 정수 복싱

방금 다음과 유사한 코드를 보았습니다.

public class Scratch
{
    public static void main(String[] args)
    {
        Integer a = 1000, b = 1000;
        System.out.println(a == b);

        Integer c = 100, d = 100;
        System.out.println(c == d);
    }
}

실행되면 다음 코드 블록이 출력됩니다.

false
true

첫 번째 이유를 이해 false합니다. 두 개체가 별도의 개체이기 때문에 ==참조를 비교합니다. 그러나 두 번째 진술이 반환되는 이유를 알 수 없습니다 true. Integer의 값이 특정 범위에있을 때 시작되는 이상한 오토 박싱 규칙이 있습니까? 여기서 무슨 일이 일어나고 있습니까?



답변

true라인은 실제로 언어 사양에 의해 보장된다. 에서 섹션 5.1.7 :

boxing되는 값 p가 true, false, a byte, \ u0000 ~ \ u007f 범위의 char 또는 -128에서 127 사이의 int 또는 짧은 숫자이면 r1과 r2를 두 개의 boxing 변환의 결과로 둡니다. 의 p. 항상 r1 == r2 인 경우입니다.

두 번째 출력 라인은 보장되지만 첫 번째 라인은 보장되지 않는다는 것을 암시합니다 (아래 인용 된 마지막 단락 참조).

이상적으로 주어진 기본 값 p를 박싱하면 항상 동일한 참조가 생성됩니다. 실제로 이것은 기존 구현 기술을 사용하여 실현 가능하지 않을 수 있습니다. 위의 규칙은 실용적인 타협입니다. 위의 마지막 절에서는 특정 공통 값을 항상 구별 할 수없는 개체로 묶어야합니다. 구현은 이들을 느리게 또는 열심히 캐시 할 수 있습니다.

다른 값의 경우,이 공식은 프로그래머 측에서 박스형 값의 식별에 대한 어떠한 가정도 허용하지 않습니다. 이렇게하면 이러한 참조의 일부 또는 전체를 공유 할 수 있습니다 (필수는 아님).

이렇게하면 특히 작은 장치에서 과도한 성능 저하없이 대부분의 일반적인 경우 동작이 원하는 동작이됩니다. 예를 들어 메모리 제한이 적은 구현은 -32K-+ 32K 범위의 정수 및 long뿐만 아니라 모든 문자와 단락을 캐시 할 수 있습니다.


답변

public class Scratch
{
   public static void main(String[] args)
    {
        Integer a = 1000, b = 1000;  //1
        System.out.println(a == b);

        Integer c = 100, d = 100;  //2
        System.out.println(c == d);
   }
}

산출:

false
true

네 첫 번째 출력은 참조를 비교하기 위해 생성됩니다. ‘a’와 ‘b’-이들은 서로 다른 두 참조입니다. 포인트 1에서는 실제로 다음과 유사한 두 개의 참조가 생성됩니다.

Integer a = new Integer(1000);
Integer b = new Integer(1000);

두 번째 출력 은가 범위 (-128에서 127)에 속할 JVM때 메모리를 절약하려고하기 때문에 생성 됩니다 Integer. 지점 2에서는 ‘d’에 대한 Integer 유형의 새로운 참조가 생성되지 않습니다. Integer 유형 참조 변수 ‘d’에 대한 새 개체를 만드는 대신 ‘c’에서 참조하는 이전에 만든 개체 만 할당합니다. 이 모든 작업은 JVM.

이러한 메모리 절약 규칙은 정수에만 적용되는 것이 아닙니다. 메모리 절약을 위해 다음 래퍼 개체의 두 인스턴스 (복싱을 통해 생성되는 동안)는 항상 기본 값이 동일한 ==입니다.

  • 부울
  • 바이트
  • 캐릭터로부터 \ u0000의\u007f(7F는 십진수 127)
  • -128 에서 127 까지의 Short 및 Integer

답변

일부 범위 (-128에서 127까지)의 정수 개체는 캐시되고 다시 사용됩니다. 이 범위를 벗어난 정수는 매번 새로운 객체를 얻습니다.


답변

예, 값이 특정 범위에있을 때 시작되는 이상한 오토 박싱 규칙이 있습니다. Object 변수에 상수를 할당 할 때 언어 정의에 새 개체를 만들어야한다는 내용이 없습니다. 캐시에서 기존 개체를 재사용 할 수 있습니다.

실제로 JVM은 일반적으로 이러한 목적을 위해 작은 정수 캐시와 Boolean.TRUE 및 Boolean.FALSE와 같은 값을 저장합니다.


답변

내 생각에 Java는 매우 일반적이기 때문에 이미 ‘박스형’인 작은 정수의 캐시를 유지하고 새 개체를 만드는 것보다 기존 개체를 재사용하는 데 많은 시간을 절약합니다.


답변

흥미로운 점입니다. 책에서 Effective Java 는 항상 자신의 클래스에 대해 같음을 재정의 할 것을 제안합니다. 또한 Java 클래스의 두 개체 인스턴스에 대한 동등성을 확인하려면 항상 equals 메소드를 사용하십시오.

public class Scratch
{
    public static void main(String[] args)
    {
        Integer a = 1000, b = 1000;
        System.out.println(a.equals(b));

        Integer c = 100, d = 100;
        System.out.println(c.equals(d));
    }
}

보고:

true
true


답변

Java에서 boxing은 Integer에 대해 -128에서 127 사이의 범위에서 작동합니다. 이 범위의 숫자를 사용하는 경우 == 연산자와 비교할 수 있습니다. 범위를 벗어난 Integer 개체의 경우 같음을 사용해야합니다.