권투와 언 박싱이란 무엇이며 트레이드 오프 란 무엇입니까?


135

명확하고 간결하며 정확한 답변을 찾고 있습니다.

좋은 설명에 대한 링크는 환영하지만 실제 답변으로 이상적입니다.


2
이것이 언어에 구애받지 않습니까?
Henk Holterman

3
@HenkHolterman 언어에 따라 다르지만 모든 언어 와 관련이있는 것은 아닙니다 . 예를 들어, 가장 역동적 인 유형의 언어와는 구분이 중요하지 않습니다. 어떤 태그를 대신 사용할 수 있는지 잘 모르겠습니다 language-but-not-type-agnostic. static-language-agnostic? 나는 그렇게 구별이 필요하다는 것을 확신하지 못한다. 메타에는 좋은 질문이 될 수 있습니다.
Keith

답변:


189

박스형 값은 기본 유형 * 주위의 최소 래퍼 데이터 구조 입니다 . 박스형 값은 일반적으로 힙의 객체에 대한 포인터로 저장됩니다 .

따라서 박스형 값은 더 많은 메모리를 사용하고 최소 두 개의 메모리 조회를 통해 액세스합니다. 한 번은 포인터를 가져오고 다른 한 번은 해당 포인터를 프리미티브로 따라갑니다. 분명히 이것은 당신이 당신의 내부 루프에서 원하는 종류의 것이 아닙니다. 반면, 박스형 값은 일반적으로 시스템의 다른 유형에서 더 잘 재생됩니다. 그것들은 언어의 일류 데이터 구조이기 때문에 다른 데이터 구조가 가지고있는 예상 메타 데이터와 구조를 가지고 있습니다.

Java 및 Haskell 일반 컬렉션에는 상자없는 값이 포함될 수 없습니다. .NET의 일반 컬렉션은 벌칙없이 상자에 넣지 않은 값을 보유 할 수 있습니다. Java의 제네릭이 컴파일 타임 유형 검사에만 사용되는 경우 .NET은 런타임에 인스턴스화 된 각 제네릭 유형에 대한 특정 클래스를 생성합니다 .

Java와 Haskell은 unboxed 배열을 가지고 있지만 다른 컬렉션보다 분명히 덜 편리합니다. 그러나 최고의 성능이 필요할 때 복싱 및 언 박싱의 오버 헤드를 피하는 것이 다소 불편합니다.

*이 논의에서 프리미티브 값은 힙의 값에 대한 포인터로 저장되는 것이 아니라 호출 스택 에 저장할 수있는 값입니다. 종종 그것은 기계 유형 (int, float 등), 구조체 및 때로는 정적 크기의 배열 일뿐입니다. .NET-land는이를 참조 형식과 달리 값 형식이라고합니다. 자바 사람들은 그것들을 원시 유형이라고 부릅니다. Haskellions는 박스형 박스라고 부릅니다.

** 나는이 답변에서 Java, Haskell 및 C #에도 중점을두고 있습니다. 그 가치가 있기 때문에 Python, Ruby 및 Javascript에는 모두 독점적으로 상자 값이 있습니다. 이것은 "모든 것이 객체입니다"접근 방식이라고도합니다.

***주의 사항 : 충분히 고급 컴파일러 / JIT는 실제로 소스를 볼 때 의미 적으로 상자에 넣은 값이 런타임에 상자에 넣지 않은 값일 수 있음을 실제로 감지 할 수 있습니다. 본질적으로, 훌륭한 언어 구현 자 덕분에 상자가 때로는 무료입니다.


박스형 값인데 왜 CLR 또는 양식 복싱 값에 어떤 이점이 있습니까?
PositiveGuy

한마디로 (ha ha), 그들은 또 다른 객체 일 뿐이며, 매우 편리합니다. 프리미티브 (적어도 자바에서는)는 Object의 자손이 아니며, 필드를 가질 수없고, 메소드를 가질 수 없으며, 일반적으로 다른 유형의 값과는 매우 다르게 동작합니다. 반면에, 그들과 함께 작업하는 것은 매우 빠르고 공간 효율적일 수 있습니다. 따라서 트레이드 오프.
Peter Burns

2
Javascript에는 unboxed int 및 float의 배열 인 유형이 지정된 배열 (새로운 UInt32Array 등)이 있습니다.
nponeccop


72

복싱 및 언 박싱은 프리미티브 값을 객체 지향 래퍼 클래스로 변환하거나 (박싱), 객체 지향 래퍼 클래스에서 프리미티브 값으로 다시 변환하는 프로세스입니다 (unboxing).

예를 들어, 자바에서는 프리미티브를 객체에만 저장할 수 없기 때문에 intInteger을 저장 하려면 값을 (박싱) 으로 변환해야 할 수도 있습니다. 당신이이 밖으로 돌아 가야 할 때 당신은 같은 값 취득 할 수 있습니다 아닌 당신이 그것을 언 박싱 할 수 있도록합니다.CollectionCollectionCollectionintInteger

복싱과 언 박싱은 본질적으로 나쁘지 는 않지만 트레이드 오프입니다. 언어 구현에 따라 프리미티브를 사용하는 것보다 속도가 느리고 메모리를 많이 사용할 수 있습니다. 그러나 더 높은 수준의 데이터 구조를 사용하고 코드의 유연성을 높일 수도 있습니다.

요즘에는 Java (및 다른 언어) "autoboxing / autounboxing"기능의 맥락에서 가장 일반적으로 논의됩니다. 다음은 오토 박싱에 대한 자바 중심 설명입니다 .


23

.Net에서 :

함수가 어떤 변수를 소비 할 것인지에 의존 할 수없는 경우가 많으므로 가장 낮은 공통 분모에서 확장되는 객체 변수를 사용해야합니다 object.

그러나 object클래스이며 그 내용을 참조로 저장합니다.

List<int> notBoxed = new List<int> { 1, 2, 3 };
int i = notBoxed[1]; // this is the actual value

List<object> boxed = new List<object> { 1, 2, 3 };
int j = (int) boxed[1]; // this is an object that can be 'unboxed' to an int

두 정보 모두 동일한 정보를 보유하지만 두 번째 목록은 더 크고 느립니다. 두 번째 목록의 각 값을 실제로 참조 인 object보류를 int.

이에 int싸여 있기 때문에 boxed라고 합니다 object. 캐스트 int백시 박스가 해제되어 다시 값으로 변환됩니다.

값 유형 (예 : all structs)의 경우 속도가 느리고 잠재적으로 더 많은 공간을 사용합니다.

참조 유형 (예 : all classes)의 경우 어쨌든 참조로 저장되므로 문제가 훨씬 적습니다.

박스형 값 유형의 또 다른 문제는 값이 아니라 박스를 다루고 있는지 확실하지 않다는 것입니다. 두 개 structs를 비교하면 값을 비교하지만 두 개 classes를 비교 하면 (기본적으로) 참조를 비교합니다. 즉, 동일한 인스턴스입니까?

박스형 값 유형을 처리 할 때 혼동 될 수 있습니다.

int a = 7;
int b = 7;

if(a == b) // Evaluates to true, because a and b have the same value

object c = (object) 7;
object d = (object) 7;

if(c == d) // Evaluates to false, because c and d are different instances

해결하기 쉽습니다.

if(c.Equals(d)) // Evaluates to true because it calls the underlying int's equals

if(((int) c) == ((int) d)) // Evaluates to true once the values are cast

그러나 상자 값을 처리 할 때주의해야 할 또 다른 사항입니다.


1
vb.net에서 등식 시맨틱의 구분이 더 명확 Object하고 등식 연산자를 구현하지는 않지만 클래스 유형은 Is연산자 와 비교할 수 있습니다 . 반대로 Int32항등 연산자와 함께 사용할 수는 있지만 사용할 수는 없습니다 Is. 이러한 구별을 통해 어떤 유형의 비교가 수행되고 있는지 훨씬 명확하게 알 수 있습니다.
supercat December

4

Boxing값 유형을 참조 유형으로 변환하는 프로세스입니다. 반면 Unboxing참조 유형을 값 유형으로 변환합니다.

EX: int i = 123;
    object o = i;// Boxing
    int j = (int)o;// UnBoxing

값 유형은 int, charstructures, enumerations입니다. 참조 유형이다 : Classes, interfaces, arrays, stringsobjects


3

.NET FCL 일반 컬렉션 :

List<T>
Dictionary<TKey, UValue>
SortedDictionary<TKey, UValue>
Stack<T>
Queue<T>
LinkedList<T>

이전 컬렉션 구현에서 boxing 및 unboxing의 성능 문제를 극복하도록 설계되었습니다.

자세한 내용은 16 장 C # (2 판)을 통한 CLR을 참조하십시오 .


1

복싱 및 언 박싱은 가치 유형이 객체로 취급 될 수 있도록합니다. 복싱은 값을 개체 참조 유형의 인스턴스로 변환하는 것을 의미합니다. 예를 들어, Int클래스이며 int데이터 유형입니다. 로 변환 int하는 Int것은 복싱의 예시이며,로 변환 Int하는 int것은 언 박싱입니다. 반면이 개념은 가비지 수집에 도움이됩니다. Unboxing은 객체 유형을 값 유형으로 변환합니다.

int i=123;
object o=(object)i; //Boxing

o=123;
i=(int)o; //Unboxing.

자바 스크립트에서을 var ii = 123; typeof ii 반환합니다 number. var iiObj = new Number(123); typeof iiObj을 반환합니다 object. typeof ii + iiObj을 반환합니다 number. 그래서 이것은 권투와 같은 자바 스크립트입니다. iiObj 값은 산술을 수행하고 상자없는 값을 반환하기 위해 자동으로 기본 숫자 (상자없는)로 변환되었습니다.
PatS

-2

다른 방법과 마찬가지로 오토 박싱은주의해서 사용하지 않으면 문제가 될 수 있습니다. 고전은 NullPointerException으로 끝나고 추적 할 수 없습니다. 디버거에서도 마찬가지입니다. 이 시도:

public class TestAutoboxNPE
{
    public static void main(String[] args)
    {
        Integer i = null;

        // .. do some other stuff and forget to initialise i

        i = addOne(i);           // Whoa! NPE!
    }

    public static int addOne(int i)
    {
        return i + 1;
    }
}

이것은 나쁜 코드 일뿐이며 오토 박스와는 관련이 없습니다. 변수 i가 조기에 초기화되었습니다. Integer i;컴파일러가 초기화를 잊었 음을 가리킬 수 있도록 빈 선언 ( )으로 지정하거나 값을 알 때까지 선언을 기다립니다.
erickson

흠, 그리고 try catch 블록 내부에서 무언가를하면 컴파일러가 무언가로 초기화하도록 강제합니다. 이것은 실제 코드가 아닙니다-어떻게 일어날 수 있는지에 대한 예입니다.
PEELY

이것은 무엇을 보여줍니까? Integer 객체를 사용해야 할 이유는 없습니다. 대신 잠재적 인 NullPointer를 처리해야합니다.
Richard Clayton
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.