안녕하세요. 성조입니다.
이번 포스팅에서는 자바 언어의 박싱과 언박싱에 대해서 정리해 보려 합니다.
혹여나 잘못된 지식 전달이 있다면 언제든지 댓글로 얘기해 주시면 감사드리겠습니다.
박싱(Boxing)
박싱은 원시 타입의 값을 해당하는 래퍼 클래스(Wrapper class)의 객체로 변환하는 것을 말한다.
각각의 원시 타입에는 해당하는 래퍼 클래스가 있어서 그 원시 타입의 값을 객체로 다룰 때 사용하는 것이 박싱이다.
'int' 타입의 래퍼 클래스는 'Integer'이며, 'double' 타입의 래퍼 클래스는 'Double'이다.
박싱은 직접 래퍼 클래스의 생성자를 호출하여 수행할 수 있지만 자바 5 버전 이후로 자동 박싱(Autoboxing)이라는 기능을 통해 이 과정을 자동으로 처리할 수 있게 됐다.
[Boxing 예제 코드]
// 직접 박싱
Integer boxedInt = new Integer(8);
// 자동 박싱
Integer autoBoxedInt = 8; // 컴파일러가 자동으로 Integer.valueOf(8)로 변환
언박싱(Unboxing)
래퍼 클래스의 객체를 원시 타입의 값으로 변환하는 것을 말한다.
래퍼 클래스의 객체를 원시 타입의 값으로 변환하는 과정을 언박싱 과정이라 한다. 언박싱 또한, 자동 언박싱(AutoUnboxing)을 통해서 자동화할 수 있다.
// 직접 언박싱
int unboxedInt = boxedInt.intValue();
// 자동 언박싱
int autoUnboxedInt = boxedInt; // 컴파일러가 자동으로 boxedInt.intValue()로 변환
박싱과 언박싱이 필요한 이유와 예시
박싱과 언박싱은 원시 타입과 참조 타입 간의 전환이 필요한 상황에서 객체 지향적 프로그래밍 기능을 활용하기 위해서 사용하거나, 메모리와 성능을 효율적으로 관리하기 위해 박싱과 언박싱이 필요하다.
자바는 기본 데이터 타입(primitive types)과 참조 데이터 타입(reference types)을 지원한다.
기본 타입의 경우 모두 메모리에 직접 값을 저장하므로 효율적일 수 있지만, 객체 지향 프로그래밍에서는 특징을 모두 활용하기 어렵다.
참조 데이터 타입의 경우 메모리에 객체의 참조(주소)를 저장한다. 그래서 객체 지향 프로그래밍의 다양한 기능을 적용시킬 수 있으나, 메모리 사용 측면에서 비효율적일 수 있다.
그래서 래퍼 클래스는 이 두 가지 타입 사이의 다리 역할을 해주는데 원시 타입을 래퍼 클래스로 박싱(Boxing)하면, 원시 타입도 객체 지향 프로그래밍에 적합하게 활용할 수 있게 된다.
'ArrayList' 같은 컬렉션은 원시 타입을 직접 담을 수 없다. 하지만 원시 타입을 래퍼 클래스로 박싱 하면 컬렉션에 저장할 수 있게 된다.
원시 타입을 래퍼 클래스로 박싱하는 예제는 다음과 같다.
[예시]
List<Integer> list = new ArrayList<>();
for (int i = 0; i < 10; i++) {
list.add(i); // i는 자동으로 Integer 객체로 박싱된다.
}
반대로, 래퍼 클래스의 값을 원시 타입처럼 취급해야 할 때는 언박싱(Unboxing)이 필요하게 된다.
언박싱을 통해 래퍼 클래스의 객체를 원시 타입의 값으로 변환시킬 수 있으며, 래퍼 클래스의 메서드를 호출하여 수행하거나, 자동 언박싱 기능을 활용해서 사용할 수 있다.
[예시]
Integer boxedInt = new Integer(123);
int unboxedInt = boxedInt.intValue(); // 수동 언박싱
int autoUnboxedInt = boxedInt; // 자동 언박싱
주의할 점
자동 박싱과 언박싱은 코드를 간결하게 해주는 장점이 있다. 하지만 다음의 문제들이 발생할 수 있다.
- 박싱된 값은 원시 타입에 비해 더 많은 메모리를 차지하며, 시간을 소요하는 문제가 있다.
- 래퍼 클래스의 경우 'null' 값을 가질 수 있지만 원시 타입의 경우 null 값을 가질 수 없어서 타입을 변환하는 과정에서 'NullPointerException'이 발생할 수 있다.
[예제 코드]
Integer boxedInt = null;
int autoUnboxedInt = boxedInt; // NullPointerException 발생.
- == 연산자 사용 시 주의
원시 타입을 비교할 때는 '==' 연산자가 값을 비교하지만 래퍼 클래스를 비교할 때는 '=='가 참조를 비교한다.
참조하는 메모리 영역이 같은 것인지를 비교하기 때문에 두 래퍼 객체의 값을 비교할 때 'equals()' 메서드를 이용해야 한다.
Integer a = 200;
Integer b = 200;
System.out.println(a == b); // 출력: false
Integer c = 100;
Integer d = 100;
System.out.println(c == d); // 출력: true
자바는 -128 ~ 127의 값을 내부적으로 Integer 객체를 재사용해서 메모리 영역에 할당하기 때문에 '==' 연산으로 비교는 가능하지만 그 이상의 값은 새로운 메모리 영역을 생성하므로 '=='로 정확하게 비교할 수 없기 때문에 다음과 같은 형식으로 값을 비교한다.
System.out.println(a.equals(b)); // 출력: true
오타나 궁금한 부분이 있다면 언제든지 댓글 남겨주시면 최대한 열심히 답변해 드리겠습니다.
감사드립니다. 다음 포스팅 때 뵙겠습니다!
'Java ☕ > Java' 카테고리의 다른 글
[Java] 접근 지정자(Access Modifier) Private/Protected/Default/Public 정리 (0) | 2023.05.29 |
---|---|
[Java] 단일 책임 원칙(Single Responsibility Principle, SRP) (0) | 2023.05.29 |
[Java] Call by Value와 Call by Reference 정리. (값 호출과 참조 호출.) (0) | 2023.05.24 |
[Java] 메소드 오버로딩과 오버라이딩 (with 아삭 한입 정리하기) (0) | 2023.05.23 |
[Java] 얕은 복사(Shallow Copy)와 깊은 복사(Deep Copy) (0) | 2021.12.14 |