[java] Java에서 오토 박싱과 언 박싱을 사용하는 이유는 무엇입니까?

Autoboxing은 Java 컴파일러가 기본 유형과 해당 객체 래퍼 클래스간에 수행하는 자동 변환입니다. 예를 들어 int를 Integer로, double을 Double로 변환하는 등의 작업이 있습니다. 변환이 다른 방식으로 진행되는 경우이를 unboxing이라고합니다.

그렇다면 왜 이것이 필요하고 자바에서 오토 박싱과 언 박싱을 사용 하는가?



답변

이것의 주된 이유를 완전히 이해하려면 약간의 컨텍스트가 필요합니다.

프리미티브 대 클래스

Java의 기본 변수에는 값 (정수, 배정 밀도 부동 소수점 이진 숫자 등)이 포함됩니다. 때문에 이 값은 다른 길이있을 수 있습니다 ,이를 포함하는 변수는 다른 길이있을 수 있습니다 (고려 floatdouble).

반면에 클래스 변수에는 인스턴스에 대한 참조포함 됩니다. 참조는 일반적으로 여러 언어에서 포인터 (또는 포인터와 매우 유사한 것)로 구현됩니다. 이런 일들은 일반적으로 상관없이 (참조하는 인스턴스의 크기, 같은 크기를 가지고 Object, String, Integer, 등).

클래스 변수의이 속성은 포함 된 참조를 (범위까지) 상호 교환 가능하게 만듭니다 . 이것은 우리가 대체 라고 부르는 것을 할 수있게합니다 . 대체로 말하자면, 특정 유형의 인스턴스를 다른 관련 유형의 인스턴스로 사용하는 String것입니다 (a 를Object 입니다 (예를 들어를로 사용).

원시 변수는 같은 방식으로 서로 교환 할 수 없습니다.Object . 이것에 대한 가장 명백한 이유 (유일한 이유는 아님)는 크기 차이입니다. 이것은이 점에서 원시 유형을 불편하게 만들지 만, 우리는 여전히 언어에서 그것들이 필요합니다 (주로 성능으로 귀결되는 이유 때문에).

제네릭 및 유형 삭제

일반 유형은 하나 이상의 유형 매개 변수 가있는 유형입니다 (정확한 숫자를 일반 배열 이라고 함 ). 예를 들어, 제네릭 유형 정의 List<T> 에는 ( 구체적인 유형 생성 ), ( ), ( ) 등이 T될 수 있는 유형 매개 변수 가 있습니다 .Object List<Object>StringList<String>IntegerList<Integer>

제네릭 유형은 비 제네릭 유형보다 훨씬 더 복잡합니다. 그들이 JVM에 급진적 인 변화 이상 바이너리 가능성이 파괴 호환성을 방지하기 위해, (초기 릴리스 이후) 자바에 소개되었을 때, 자바의 창조자는 최소 침습적 방법으로 일반적인 유형을 구현하기로 결정 : 모든 콘크리트 유형의 List<T>실제로 (이진에 해당하는)로 컴파일됩니다 ( List<Object>다른 유형의 경우 바운드는 이외의 것이 될 수 Object있지만 요점을 얻습니다). 이 과정에서 일반 arity 및 유형 매개 변수 정보가 손실 되므로 유형 삭제 라고합니다. .

두 가지를 합치면

이제 문제는 위의 현실의 조합은 다음과 같은 경우 List<T>가됩니다 List<Object>모든 경우에, 다음T 항상 직접 할당 할 수있는 유형이어야합니다Object . 다른 것은 허용 할 수 없습니다. 이전에 말했듯이,는 int, floatdouble상호 교환 Object할 수 없기 때문에 List<int>, List<float>또는 List<double>(JVM에 훨씬 더 복잡한 제네릭 구현이 존재하지 않는 한) 있을 수 없습니다 .

그러나 Java는 Integer, FloatDouble 있는 그들을 효과적으로 대용하고, 클래스 인스턴스에서 이러한 프리미티브를 포장 Object하여, 프리미티브와 간접적으로 업무에 제네릭 형식을 허용 (당신이 있기 때문에뿐만 아니라 있습니다 List<Integer>, List<Float>, List<Double>등).

Integer에서 int, Float에서 a float등 을 만드는 과정을 boxing 이라고 합니다. 그 반대를 unboxing 이라고 합니다. 프리미티브를 사용할 때마다 박스 프리미티브를 사용하는 Object것이 불편하기 때문에 언어가이를 자동으로 수행 하는 경우가 있습니다.이를 오토 박싱 이라고합니다. . 합니다.


답변

Auto Boxing 은 원시 데이터 유형을 래퍼 클래스 객체로 변환 하는 데 사용 됩니다. 래퍼 클래스는 기본 유형에서 수행 할 광범위한 기능을 제공합니다. 가장 일반적인 예는 다음과 같습니다.

int a = 56;
Integer i = a; // Auto Boxing

그것은 필요 쉽게 권투 언 박싱 처리됩니다 직접 쓰기 코드와 JVM을 할 수 있기 때문에 프로그래머.

Auto Boxing은 java.util.Collection 유형으로 작업 할 때도 유용합니다. 기본 유형의 컬렉션을 생성하려는 경우 기본 유형의 컬렉션을 직접 생성 할 수 없으며 Object의 컬렉션 만 생성 할 수 있습니다. 예 :

ArrayList<int> al = new ArrayList<int>(); // not supported 

ArrayList<Integer> al = new ArrayList<Integer>(); // supported 
al.add(45); //auto Boxing 

래퍼 클래스

Java의 8 가지 기본 유형 (byte, short, int, float, char, double, boolean, long)은 각각 별도의 Wrapper 클래스와 관련되어 있습니다. 이러한 Wrapper 클래스에는 기본 데이터 유형에 대한 유용한 작업을 미리 정의하기위한 미리 정의 된 메서드가 있습니다.

의 사용 래퍼 클래스

String s = "45";
int a = Integer.parseInt(s); // sets the value of a to 45.

Wrapper 클래스가 제공하는 유용한 기능이 많이 있습니다. 여기 에서 자바 문서를 확인 하세요.

Unboxing 은 래퍼 클래스 객체를 다시 원시 유형으로 변환하는 Auto Boxing과 반대입니다. 이것은 JVM에 의해 자동으로 수행되므로 특정 작업에 래퍼 클래스를 사용한 다음 기본 형식으로 인해 처리 속도가 빨라지므로 기본 형식으로 다시 변환 할 수 있습니다. 예 :

Integer s = 45;
int a = s; auto UnBoxing;

개체와 함께 작동하는 컬렉션의 경우 자동 언 박싱 만 사용됩니다. 방법은 다음과 같습니다.

ArrayList<Integer> al = new ArrayList<Integer>();
al.add(45);

int a = al.get(0); // returns the object of Integer . Automatically Unboxed . 


답변

원시 (비 객체) 유형에는 효율성에 대한 정당성이 있습니다.

기본 유형 int, boolean, double은 즉각적인 데이터 인 반면 Objects는 참조입니다. 따라서 필드 (또는 변수)

int i;
double x;
Object s;

로컬 메모리 4 + 8 + 8이 필요합니까? 객체의 경우 메모리에 대한 참조 (주소) 만 저장됩니다.

Object 래퍼 Integer, Double및 기타를 사용하면 힙 메모리의 일부 Integer / Double 인스턴스에 대한 참조 인 간접 참조가 도입됩니다.

권투가 필요한 이유는 무엇입니까?

그것은 상대적 범위의 문제입니다. 미래의 자바에서는 ArrayList<int>, 리프팅 기본 유형 을 가질 수 있도록 계획되어 있습니다 .

답변 : 현재 ArrayList는 Object에 대해서만 작동하며, 객체 참조를위한 공간을 확보하고 마찬가지로 가비지 수집을 관리합니다. 따라서 제네릭 유형 은 Object 자식입니다. 따라서 부동 소수점 값의 ArrayList를 원하면 Double 객체에 double을 래핑해야합니다.

여기서 Java는 템플릿이있는 기존 C ++와 다릅니다. C ++ 클래스 vector<string>, vector<int> 는 두 개의 컴파일 제품을 만듭니다. Java 디자인은 하나의 ArrayList.class를 갖기 위해 사용되었으며 모든 매개 변수 유형에 대해 새로 컴파일 된 제품이 필요하지 않았습니다.

따라서 Object one에 대한 권투없이 매개 변수 유형이 발생할 때마다 클래스를 컴파일해야합니다. 구체적으로 말하면 모든 컬렉션 또는 컨테이너 클래스에는 Object, int, double, boolean 버전이 필요합니다. Object 버전은 모든 하위 클래스를 처리합니다.

실제로 이러한 다양 화의 필요성은 int, char, double에서 작동하는 IntBuffer, CharBuffer, DoubleBuffer 등의 Java SE에 이미 존재했습니다. 일반적인 소스에서 이러한 소스를 생성 하여 해키 방식으로 해결되었습니다 .


답변

JDK 5부터 자바는 오토 박싱과 오토 언 박싱이라는 두 가지 중요한 기능을 추가했습니다. AutoBoxing 은 이러한 객체가 필요할 때마다 기본 유형이 동등한 래퍼에 자동으로 캡슐화되는 프로세스입니다. 객체를 명시 적으로 구성 할 필요는 없습니다. 자동 언 박싱 은 값이 필요할 때 캡슐화 된 개체의 값이 유형 래퍼에서 자동으로 추출되는 프로세스입니다. intValue () 또는 doubleValue () 와 같은 메서드를 호출 할 필요가 없습니다 .

오토 박싱 및 자동 언 박싱의 추가는 작성 알고리즘을 크게 단순화 하여 미끼를 수동으로 박싱하고 값을 언 박싱하는 것을 제거합니다. 실수피하는 것도 도움이됩니다 . 객체에서만 작동하는 제네릭 에게도 매우 중요 합니다. 마지막으로, 오토 박싱은 Collections Framework 와의 작업을 용이하게합니다 .


답변

왜 우리는 (un) boxing을 가지고 있습니까?

프리미티브와 OO (Object Oriented) 대안을 더 편안하고 덜 장황하게 혼합하는 코드를 작성합니다.

프리미티브와 OO 대안이있는 이유는 무엇입니까?

기본 형식은 C #과 달리 클래스가 아니므로 하위 클래스가 Object아니므로 재정의 할 수 없습니다.

우리는 int성능상의 이유 와 같은 프리미티브와 OO 프로그래밍의 이점 Object과 같은 대안 Integer을 가지고 있으며 사소한 점으로 유틸리티 상수 및 메서드 (Integer.MAX_VALUE 및 Integer.toString(int))에 대한 좋은 위치를 갖습니다 .

OO 이점은 Generics ( List<Integer>)에서 가장 쉽게 볼 수 있지만 이에 국한되지는 않습니다. 예를 들면 다음과 같습니다.

Number getMeSome(boolean wantInt) {

    if (wantInt) {
        return Integer.MAX_VALUE;
    } else {
        return Long.MAX_VALUE;
    }
}


답변

일부 데이터 구조는 기본 유형이 아닌 객체 만 허용 할 수 있습니다.

예 : HashMap의 키.

자세한 내용은이 질문을 참조하십시오 : HashMap 및 int as key

NULL이 될 수있는 데이터베이스의 “int”필드와 같은 다른 좋은 이유가 있습니다. Java의 int는 null 일 수 없습니다. 정수 참조는 할 수 있습니다. 오토 박싱 및 언 박싱은 변환에서 불필요한 코드를 작성하지 않도록하는 기능을 제공합니다.


답변

그들은 다른 유형이기 때문에 편리합니다. 성능은 기본 유형을 갖는 이유 일 수 있습니다.