IT

Java의 이상한 정수 상자

itgroup 2022. 10. 18. 21:39
반응형

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오브젝트이기 의 오브젝트는 2개의 오브젝트로 구성되어 있습니다.==을 사용하다 왜 두알 가 없어요.trueInteger 값이 특정 범위에 있을 때 실행되는 이상한 자동 상자 규칙이 있습니까?게게무 슨슨?

true회선은 실제로 언어 사양에 의해 보증됩니다.섹션 5.1.7부터:

박스화 되는 값 p가 true, false, 바이트, \u0000 ~\u007f 의 char, 또는 -128 ~127 의 int 또는 쇼트 번호의 경우, r1 및 r2 는 p 의 2 개의 박스화 변환의 결과라고 합니다.r1 == r2인 경우는 항상 있습니다.

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

이상적으로는 특정 원시 값 p를 상자화하면 항상 동일한 참조가 생성됩니다.실제로는 기존 구현 기법으로는 가능하지 않을 수 있습니다.위의 규칙은 실용적인 절충안이다.위의 마지막 절에서는 특정 공통값을 항상 구분할 수 없는 객체로 분류해야 합니다.구현은 이를 게으르거나 열심히 캐싱할 수 있습니다.

다른 값의 경우, 이 공식은 프로그래머 측의 박스형 값의 아이덴티티에 대한 가정을 허용하지 않습니다.이를 통해 이러한 참조의 일부 또는 전부를 공유할 수 있습니다(필요하지는 않습니다).

이것에 의해, 대부분의 경우, 특히 소형 디바이스의 퍼포먼스 저하가 불필요하게 발생하지 않고, 동작이 바람직한 동작임을 확인할 수 있습니다.예를 들어 메모리 제한이 적은 구현에서는 -32K ~ +32K 범위의 정수 및 길이뿐만 아니라 모든 문자 및 짧은 문자도 캐시할 수 있습니다.

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에서는, 실제로는 다음의 2개의 참조가 작성됩니다.

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

은 " " "가 되었습니다.JVM절약을 노력합니다.Integer입니다.2번 'd'는 정수입니다.Integer 유형 참조 변수 'd'에 대한 새 개체를 만드는 대신 'c'에서 참조하는 이전에 만든 개체만 할당했습니다.은 <고객명>님에 의해 .JVM

이러한 메모리 절약 규칙은 Integer에만 적용되는 것이 아닙니다.메모리 절약을 위해 다음과 같은 래퍼 개체의 두 인스턴스는 항상 ==이며, 기본 값은 동일합니다.

  • 부울
  • 바이트
  • \u0000 ~의 문자\u007f이다) (7f는 10진수 127이다)
  • -128 ~ 127의 짧은 정수

일정 범위의 정수 객체(아마 -128~127)는 캐시되어 재사용됩니다.이 범위를 벗어나는 정수는 매번 새 개체를 가져옵니다.

Integer Cache는 기본적으로 다음과 같은 목적으로 Java 버전5에서 도입된 기능입니다.

  1. 메모리 공간 절약
  2. 퍼포먼스의 향상.
Integer number1 = 127;
Integer number2 = 127;

System.out.println("number1 == number2" + (number1 == number2); 

출력: True


Integer number1 = 128;
Integer number2 = 128;

System.out.println("number1 == number2" + (number1 == number2);

출력: False

어떻게?

실제로 Integer 객체에 값을 할당하면 후드 뒤에서 자동 프로모션이 수행됩니다.

Integer object = 100;

실제로는 Integer.valueOf() 함수를 호출하고 있습니다.

Integer object = Integer.valueOf(100);

★★★★★★★★★★★★★★★★의 상세valueOf(int)

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

설명:

이 메서드는 항상 -128 ~127 범위의 값을 캐시하며 이 범위를 벗어나는 다른 값을 캐시할 수 있습니다.

-128 ~ 127 범위의 값이 필요한 경우 매번 일정한 메모리 위치를 반환합니다.단, 127보다 큰 값이 필요한 경우

return new Integer(i);

개체를 시작할 때마다 새 참조를 반환합니다.


나, further further further further further further further,==Java 연산자는 값이 아닌 두 개의 메모리 참조를 비교하기 위해 사용됩니다.

Object11000달러 6달러
Object21020년 6월

Object1 == Object2False메모리 위치는 다르지만 값이 같기 때문입니다.

네, 값이 특정 범위에 있을 때 적용되는 이상한 자동 상자 규칙이 있습니다.개체 변수에 상수를 할당할 때 언어 정의에서 새 개체를 생성해야 한다는 내용은 없습니다.캐시에서 기존 개체를 재사용할 수 있습니다.

실제로 JVM은 보통 이 목적을 위해 부울 등의 값뿐만 아니라 작은 정수 캐시도 저장합니다.TRUE 및 Boolean.거짓의.

내 생각에 Java는 이미 '상자'로 되어 있는 작은 정수의 캐시를 보관하고 있는 것 같다.왜냐하면 이러한 정수는 매우 일반적이고 기존 객체를 다시 사용하는 것이 새로운 객체를 만드는 것보다 훨씬 많은 시간을 절약할 수 있기 때문이다.

그것은 흥미로운 점이다.책에서는 Effective Java는 항상 자신의 클래스에 대해 동등함을 재정의할 것을 제안합니다.또한 Java 클래스의 두 객체인스턴스의 동일성을 체크하려면 항상 동일한 방법을 사용합니다.

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

Integer 참조에 int 리터럴을 직접 할당하는 것은 자동 박스의 한 예입니다.여기서 오브젝트 변환 코드에 대한 리터럴 값은 컴파일러에 의해 처리됩니다.

컴파일 가 변환됩니다.Integer a = 1000, b = 1000;로로 합니다.Integer a = Integer.valueOf(1000), b = Integer.valueOf(1000);.

렇렇 so so so soInteger.valueOf()method는 실제로 정수 객체를 제공합니다.메서드의 소스 코드를 보면 메서드가 -128 ~127(표준) 범위의 정수 객체를 캐시하는 것을 명확하게 알 수 있습니다.

/**
 * 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) {
    if (i >= IntegerCache.low && i <= IntegerCache.high)
        return IntegerCache.cache[i + (-IntegerCache.low)];
    return new Integer(i);
}

새로운 오브젝트를 하여 반환하는 " " " 를 사용합니다.Integer.valueOf() Integer에서 합니다.IntegerCache127번으로 하겠습니다. -128을 사용하다

Java는 이러한 정수 개체를 캐시합니다. 왜냐하면 이 범위의 정수는 일상 프로그래밍에서 많이 사용되기 때문에 간접적으로 메모리를 절약할 수 있습니다.

캐시는 스태틱블록 때문에 클래스가 메모리에 로드되면 처음 사용할 때 초기화됩니다.는 캐시의 최대 범위를 할 수 .-XX:AutoBoxCacheMaxJVM 션 j

정수이다.에는 Integer Cache도 .ByteCache, ShortCache, LongCache, CharacterCache★★★★★★에Byte, Short, Long, Character각각 다음과 같다.

자세한 내용은 제 기사 Java Integer Cache - Why Integer.valueOf(127) == Integer.valueOf(127) Is True를 참조하십시오.

Java에서 박스는 -128에서 127 사이의 정수 범위에서 작동합니다.이 범위의 숫자를 사용하는 경우 == 연산자와 비교할 수 있습니다.범위를 벗어나는 정수 객체의 경우 equals를 사용해야 합니다.

「 」의 하면,Integerclass, 다음과 같이 메서드의 소스를 찾을 수 있습니다.

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

알 수 있어요.Integer128)(으)의 입니다.Integer.low ( 127 ( )Integer.high는, 는 자동 박스 처리 중에 참조되는 동일한 객체입니다. 클래스가 있는 을 볼 수 있습니다.IntegerCacheInteger 어레이: "private static inner" 및 "private static inner"의 내부 입니다.Integer를 누릅니다

이 이상한 상황을 이해하는 데 도움이 될 수 있는 또 다른 흥미로운 예가 있습니다.

public static void main(String[] args) throws ReflectiveOperationException {
    Class cache = Integer.class.getDeclaredClasses()[0];
    Field myCache = cache.getDeclaredField("cache");
    myCache.setAccessible(true);

    Integer[] newCache = (Integer[]) myCache.get(cache);
    newCache[132] = newCache[133];

    Integer a = 2;
    Integer b = a + a;
    System.out.printf("%d + %d = %d", a, a, b); // The output is: 2 + 2 = 5
}

Java 5에서는 메모리를 절약하고 Integer 타입 오브젝트 핸들링의 성능을 향상시키는 새로운 기능이 도입되었습니다.정수 개체는 내부적으로 캐시되고 동일한 참조 개체를 통해 재사용됩니다.

  1. 이는 –127 ~ +127 범위의 정수 값(최대 정수 값)에 적용됩니다.

  2. 이 정수 캐시는 자동 상자에 대해서만 작동합니다.정수 개체는 생성자를 사용하여 빌드될 때 캐시되지 않습니다.

상세한 것에 대하여는, 아래의 링크를 참조해 주세요.

정수 캐시 상세

★★Integer에는 JLS 5.1.7. Boxing Conversion에서 요구되는 -128 ~127 범위의 값의 캐시가 포함되어 있습니다.이 때문에,==Integer 값을 얻을 수 있습니다.또, 2개의 「S」를 하면, 2개의 「S」가 됩니다.Integer이 범위를 벗어나면 2개의 다른 값을 얻을 수 있습니다.

JVM 매개 변수를 변경하여 캐시 상한을 늘릴 수 있습니다.

-XX:AutoBoxCacheMax=<cache_max_value>

또는

-Djava.lang.Integer.IntegerCache.high=<cache_max_value>

내부 클래스 참조:

/**
 * Cache to support the object identity semantics of autoboxing for values
 * between -128 and 127 (inclusive) as required by JLS.
 *
 * The cache is initialized on first usage.  The size of the cache
 * may be controlled by the {@code -XX:AutoBoxCacheMax=<size>} option.
 * During VM initialization, java.lang.Integer.IntegerCache.high property
 * may be set and saved in the private system properties in the
 * sun.misc.VM class.
 */
private static class IntegerCache {
    static final int low = -128;
    static final int high;
    static final Integer cache[];

    static {
        // high value may be configured by property
        int h = 127;
        String integerCacheHighPropValue =
            sun.misc.VM.getSavedProperty("java.lang.Integer.IntegerCache.high");
        if (integerCacheHighPropValue != null) {
            try {
                int i = parseInt(integerCacheHighPropValue);
                i = Math.max(i, 127);
                // Maximum array size is Integer.MAX_VALUE
                h = Math.min(i, Integer.MAX_VALUE - (-low) -1);
            } catch( NumberFormatException nfe) {
                // If the property cannot be parsed into an int, ignore it.
            }
        }
        high = h;

        cache = new Integer[(high - low) + 1];
        int j = low;
        for(int k = 0; k < cache.length; k++)
            cache[k] = new Integer(j++);

        // range [-128, 127] must be interned (JLS7 5.1.7)
        assert IntegerCache.high >= 127;
    }

    private IntegerCache() {}
}

언급URL : https://stackoverflow.com/questions/3130311/weird-integer-boxing-in-java

반응형