박싱(Boxing)이란?
박싱은 값 타입(value type)을 참조 타입(reference type)으로 변환하는 과정입니다. 이때 변환은 암시적(implicit)으로 이루어지며, 개발자가 별도의 캐스팅 코드를 작성하지 않아도 자동으로 처리됩니다.
박싱이 발생하면 값 타입의 데이터는 힙(heap) 영역에 새로운 객체로 할당되고, 스택(stack)에 있던 원래 값은 해당 힙 객체를 가리키는 참조로 대체됩니다. 즉, 단순한 타입 변환이 아니라 새로운 객체 생성이 수반되기 때문에 성능에 영향을 줄 수 있습니다.
언박싱(Unboxing)이란?
언박싱은 박싱을 통해 생성된 참조 타입 객체를 다시 원래의 값 타입으로 되돌리는 과정입니다. 언박싱은 박싱과 달리 명시적(explicit) 변환이 필요하며, 반드시 캐스트 연산자를 사용해야 합니다.
주의할 점은 언박싱 시 지정하는 타입이 박싱 당시의 원래 값 타입과 정확히 일치해야 한다는 것입니다. 일치하지 않으면 런타임에 InvalidCastException이 발생합니다.
기본 예제
다음 코드는 int 값 타입이 박싱과 언박싱을 거치는 기본적인 흐름을 보여줍니다.
// 값 타입 선언 int myVal = 12; // 박싱: 값 타입 → 참조 타입 (암시적 변환) object myBoxed = myVal; // 언박싱: 참조 타입 → 값 타입 (명시적 변환) int myUnBoxed = (int)myBoxed;
ArrayList에서의 박싱과 언박싱
제네릭이 도입되기 전에는 ArrayList와 같은 비제네릭 컬렉션에 값을 추가할 때마다 박싱이 발생했습니다. 다음 예제를 살펴보겠습니다.
int a = 5; ArrayList arr = new ArrayList(); // 박싱: int 값이 object로 변환되어 저장됨 arr.Add(a); // 언박싱: object를 다시 int로 변환 int b = (int)arr[0];
위 코드에서 arr.Add(a)가 호출되면 int 값 5는 자동으로 object 타입으로 박싱되어 저장됩니다. 그리고 값을 꺼낼 때는 (int)arr[0]처럼 명시적으로 언박싱해야 합니다.
성능 관련 팁
박싱과 언박싱은 힙 메모리 할당과 가비지 컬렉션(GC) 부담을 유발하므로, 반복문이나 대량의 데이터를 처리하는 코드에서는 피하는 것이 좋습니다. .NET 2.0 이상에서는 제네릭 컬렉션(List<int>, Dictionary<TKey, TValue> 등)을 사용하면 박싱 없이 값 타입을 안전하게 저장할 수 있습니다.