수색…


소개

Autoboxing 은 Java 컴파일러가 기본 유형과 해당 객체 래퍼 클래스간에 자동으로 변환하는 것입니다. 예를 들어, int -> Integer, double -> Double ... 변환이 다른 방법으로 진행되면 이것을 unboxing이라고합니다. 일반적으로 이것은 콜렉션에서 설정하기 전에 boxing primitive 유형이 필요한 경우 Object가 아닌 다른 것을 보유 할 수없는 콜렉션에서 사용됩니다.

비고

Autoboxing은 코드에서 자주 사용하면 성능 문제가 발생할 수 있습니다.

int와 Integer를 서로 바꾸어 사용할 수 있습니다.

유틸리티 클래스와 함께 제네릭 형식을 사용할 때 개체 유형으로 지정된 경우 기본 형식과 동일하지 않기 때문에 숫자 형식이별로 도움이되지 않는 경우가 종종 있습니다.

List<Integer> ints = new ArrayList<Integer>();
Java SE 7
List<Integer> ints = new ArrayList<>();

다행스럽게도, Integer 대신에 int 평가되는 표현식을 사용할 수 있습니다.

for (int i = 0; i < 10; i++)
    ints.add(i);

ints.add(i); 명령문은 다음과 같습니다.

ints.add(Integer.valueOf(i));

그리고 JVM이 숫자 캐싱 범위 내에있을 때 동일한 Integer 객체를 캐시하는 등 Integer#valueOf 속성을 유지합니다.

적용 대상 :

  • byteByte
  • short Short
  • floatFloat
  • doubleDouble
  • long Long
  • charCharacter
  • booleanBoolean

그러나 모호한 상황에서주의를 기울여야합니다. 다음 코드를 살펴보십시오.

List<Integer> ints = new ArrayList<Integer>();
ints.add(1);
ints.add(2);
ints.add(3);
ints.remove(1); // ints is now [1, 3]

java.util.List 인터페이스는 remove(int index) ( List 인터페이스 메소드)와 remove(Object o) ( java.util.Collection 에서 상속 된 java.util.Collection )를 모두 포함합니다. 이 경우 복싱이 수행되지 않고 remove(int index) 가 호출됩니다.

autoboxing으로 인한 이상한 Java 코드 동작에 대한 또 하나의 예 -128 에서 127 사이의 값을 갖는 정수 :

Integer a = 127;
Integer b = 127;
Integer c = 128;
Integer d = 128;
System.out.println(a == b); // true
System.out.println(c <= d); // true
System.out.println(c >= d); // true
System.out.println(c == d); // false

때문에 발생합니다 >= 연산자를 암시 적으로 호출 intValue() 반환 int 하면서 == 참조가 아닌 비교 int 값을.

기본적으로 Java는 [-128, 127] 범위의 값을 캐시하므로 연산자의 == 작동합니다.이 범위의 Integers 는 해당 값이 동일한 경우 동일한 객체를 참조하기 때문입니다. 캐시 가능 범위의 최대 값은 -XX:AutoBoxCacheMax JVM 옵션을 사용하여 정의 할 수 있습니다. 따라서 -XX:AutoBoxCacheMax=1000 프로그램을 실행하면 다음 코드가 true 를 인쇄 true .

Integer a = 1000;
Integer b = 1000;
System.out.println(a == b); // true

if 문에서 부울 사용

자동 언 박싱으로 인해 if 문에 Boolean 을 사용할 수 있습니다.

Boolean a = Boolean.TRUE;
if (a) { // a gets converted to boolean
    System.out.println("It works!");
}

그건 for 문에서 조건을하는 do while while 작동합니다.

Booleannull 인 경우 변환시 NullPointerException 이 발생합니다.

자동 언 박싱으로 인해 NullPointerException이 발생할 수 있습니다.

이 코드는 다음과 같이 컴파일됩니다.

Integer arg = null;
int x = arg;

그러나 런타임시 두 번째 행에서 java.lang.NullPointerException 을 사용하여 충돌합니다.

문제는 원시 intnull 값을 가질 수 없다는 것입니다.

이것은 최소한의 예이지만 실제로는 더 정교한 형태로 나타납니다. NullPointerException 은 그다지 직관적이지 않으며 종종 이러한 버그를 찾아내는 데 거의 도움이되지 않습니다.

autoboxing과 auto-unboxing에주의를 기울여 런타임시 unboxed 값에 null 값이 없는지 확인하십시오.

Autoboxing의 메모리 및 전산 오버 헤드

Autoboxing은 상당한 메모리 오버 헤드를 초래할 수 있습니다. 예 :

Map<Integer, Integer> square = new HashMap<Integer, Integer>();
for(int i = 256; i < 1024; i++) {
    square.put(i, i * i); // Autoboxing of large integers
}

일반적으로 상당한 양의 메모리를 소비합니다 (6k 실제 데이터의 경우 약 60kb).

또한 박스형 정수는 일반적으로 메모리에 추가 왕복이 필요하므로 CPU 캐시의 효율성이 떨어집니다. 위의 예에서 액세스 된 메모리는 메모리의 완전히 다른 영역에있을 수있는 5 개의 다른 위치, 즉 HashMap 객체, 2.지도의 Entry[] table 객체, 3. Entry 객체, 4. entrys key 객체 (기본 키를 boxing), 5. entrys value 객체 (boxing the primitive value).

class Example {
  int primitive; // Stored directly in the class `Example`
  Integer boxed; // Reference to another memory location
}

독서 boxedprimitive 하나만 액세스하는 두 개의 메모리 액세스가 필요합니다.

이지도에서 데이터를 가져올 때 무고한 코드

int sumOfSquares = 0;
for(int i = 256; i < 1024; i++) {
    sumOfSquares += square.get(i);
}

다음과 같습니다.

int sumOfSquares = 0;
for(int i = 256; i < 1024; i++) {
    sumOfSquares += square.get(Integer.valueOf(i)).intValue();
}

일반적으로 위의 코드는 모든 Map#get(Integer) 연산에 대해 Integer 객체의 생성 및 가비지 수집 을 발생시킵니다. 자세한 내용은 아래 참고 사항을 참조하십시오.

이러한 오버 헤드를 줄이기 위해 여러 라이브러리가 복싱이 필요 없는 기본 유형의 최적화 된 콜렉션을 제공합니다. 권투 오버 헤드를 피하는 것 외에도이 수집에는 항목 당 약 4 배 적은 메모리가 필요합니다. Java 핫스팟 힙 대신 스택의 객체로 작업하여 오토 박싱을 최적화 할 수 있지만 메모리 오버 헤드와 결과 메모리 간접 지정을 최적화하는 것은 불가능합니다.

Java 8 스트림에는 또한 복싱이 필요없는 IntStream 과 같은 기본 데이터 유형에 대해 최적화 된 인터페이스가 있습니다.

주 : 전형적인 Java 런타임은 valueOf 팩토리 메소드 및 autoboxing에 의해 사용되는 Integer 및 기타 원시 래퍼 객체의 간단한 캐시를 유지 관리합니다. Integer 의 경우이 캐시의 기본 범위는 -128에서 +127입니다. 일부 JVM은 캐시 크기 / 범위를 변경하기위한 JVM 명령 행 옵션을 제공합니다.

Integer와 int가 서로 교환 할 수있을 때 다른 경우

사례 1 : 메서드 인수 대신 사용.

메소드가 인수로서 래퍼 클래스의 객체를 필요로하는 경우, 인수는 해당 기본 유형의 변수를 전달할 수 있으며 그 반대의 경우도 가능합니다.

예:

int i;
Integer j;
void ex_method(Integer i)//Is a valid statement
void ex_method1(int j)//Is a valid statement

사례 2 : 반환 값을 전달하는 중 :

메소드가 프리미티브 유형 변수를 반환하면 해당 래퍼 클래스의 객체는 반환 값으로 교환 가능하게 전달 될 수 있으며 그 반대의 경우도 마찬가지입니다.

예:

int i;
Integer j;
int ex_method()
{...
return j;}//Is a valid statement
Integer ex_method1()
{...
return i;//Is a valid statement
}

사례 3 : 작업 수행 중.

숫자에 대한 연산을 수행 할 때마다 프리미티브 유형 변수와 각 래퍼 클래스의 객체는 서로 바꿔서 사용할 수 있습니다.

int i=5;
Integer j=new Integer(7);
int k=i+j;//Is a valid statement
Integer m=i+j;//Is also a valid statement

Pitfall : 래퍼 클래스의 객체를 초기화하거나 값을 할당해야합니다.

래퍼 클래스 객체와 프리미티브 변수를 상호 교환 적으로 사용하는 것은 결코 잊지 않거나 초기화하지 않거나 래퍼 클래스 객체에 값을 할당하지 않으면 런타임에 널 포인터 예외가 발생할 수 있습니다.

예:

public class Test{
    Integer i;
    int j;
    public void met()
    {j=i;//Null pointer exception
    SOP(j);
    SOP(i);}   
    public static void main(String[] args)
    {Test t=new Test();
    t.go();//Null pointer exception
    }

위의 예제에서 객체의 값은 할당되지 않았고 초기화되지 않았으므로 런타임에 프로그램이 null 포인터 예외로 실행됩니다. 위의 예제에서 알 수 있듯이 객체의 값은 초기화되지 않고 할당되지 않은 상태로 두어서는 안됩니다.



Modified text is an extract of the original Stack Overflow Documentation
아래 라이선스 CC BY-SA 3.0
와 제휴하지 않음 Stack Overflow