🔍 Wrapper Class
프로그래밍을 하다 보면 기본 타입의 데이터를 객체로 표현해야 하는 경우가 있다.
이럴 때 기본 타입을 객체로 다루기 위해 사용하는 클래스들을 래퍼 클래스(Wrapper Class)라고 한다.
자바의 모든 기본 타입은 값을 갖는 객체로 생성할 수 있다.
이런 객체를 포장 객체라고도 하는데 기본 타입의 값을 내부에 두고 포장하는 것처럼 보이기 때문이다.
포장된 물건은 바꿀 수 없듯이, 래퍼 클래스로 감싸고 있는 기본 타입 값은 외부에서 변경이 불가능하다.
만약 값을 바꾸고 싶다면 새로운 포장 객체를 생성해야 한다.
래퍼 클래스는 java.lang 패키지에 포함되어 제공된다.
래퍼 클래스를 이용하면 각 타입에 해당하는 데이터를 파라미터로 전달받아 해당 값을 가지는 객체로 만들어준다.
기본 타입 | 래퍼 클래스 |
byte | Byte |
short | Short |
int | Integer |
long | Long |
float | Float |
double | Double |
char | Character |
boolean | Boolean |
📦 Boxing & UnBoxing
래퍼 클래스를 통해 값을 포장하여 객체로 만들 수 있지만 래퍼 클래스는 산술 연산을 위해 정의된 클래스가 아니기 때문에 래퍼 클래스 인스턴스에 저장된 값을 직접 변경이 불가능하다. 그래서 래퍼 클래스를 언박싱 한 뒤에 값을 변경한 뒤 박싱해야 하는 중간 단계를 거쳐야 한다.
- Boxing : 기본 타입의 데이터 → 래퍼 클래스의 인스턴스로 변환
- UnBoxing : 래퍼 클래스의 인스턴스에 저장된 값 → 기본 타입의 데이터로 변환
💡 예시
// 박싱
Integer num = new Integer(20); // Integer 래퍼 클래스 num 에 20 의 값을 저장
// 언박싱 (intValue)
int n = num.intValue(); // 래퍼 클래스 num 의 값을 꺼내 가져온다.
// 박싱
n = n + 100; // 120
num = new Integer(n);
📤 각 Wrapper 타입의 클래스 언박싱 메소드
메소드 | 반환값 | 설명 |
booleanValue() | boolean | 기본형 데이터를 문자열로 바꾼 뒤에 반환 |
byteValue() | byte | 객체의 값을 byte값으로 변환하여 변환 |
doubleValue() | double | 객체의 값을 double 값으로 변환하여 변환 |
floatValue() | float | 객체의 값을 float 값으로 변환하여 변환 |
intValue() | int | 객체의 값을 int 값으로 변환하여 변환 |
longValue() | long | 객체의 값을 long 값으로 변환하여 변환 |
shortValue() | short | 객체의 값을 short 값으로 변환하여 변환 |
📦 Auto Boxing & Auto UnBoxing
JDK 1.5 부터는 자바 컴파일러가 자동으로 박싱, 언박싱을 처리해주기 시작했다.
// 기본 박싱 & 언박싱
Integer num = new Integer(17); // boxing
int n = num.intValue(); // unboxing
// 오토 박싱 & 언박싱
Integer num = 17; // new Integer() 생략
int n = num; // intValue() 생략
오토 박싱을 이용하면 new 키워드를 사용하지 않아도 자동으로 인스턴스를 생성할 수 있으며
언박싱 메소드를 사용하지 않아도 인스턴스에 저장된 값을 바로 참조할 수 있게 된다.
➕ Wrapper Class 연산
오토 박싱 & 언박싱을 통해 래퍼 객체는 직접 연산이 가능해지게 된다.
원래는 래퍼 클래스는 직접 연산이 불가능 하지만 컴파일러가 스스로 판단해 자동으로 언박싱하여 연산하기 때문이다.
Integer num1 = new Integer(7); // 박싱
Integer num2 = new Integer(3); // 박싱
int int1 = num1.intValue(); // 언박싱
int int2 = num2.intValue(); // 언박싱
// auto unboxing & auto boxing
Integer result1 = num1 + num2; // 10
Integer result2 = int1 - int2; // 4
int result3 = num1 * num2; // 21
💡NullPointerException 에러
래퍼 객체를 다룰 때 가장 많이 볼 수 있는 에러 예외 메시지이다.
null 값을 가지는 Wrapper Class 객체와 기본형 값을 연산할 경우, NullPointerException이 발생한다.
이는 피연산자에 기본형 int 값이 존재하여 Wrapper Class 객체를 auto unboxing 하는 중에 발생하는 에러이다.
Integer num = null;
int result = num + 5; // NullPointerException 발생!
- num은 Integer 타입이지만 null을 가지고 있다.
- result = num+5; 이 부분에서 자바는 num을 자동으로 int로 변환하려고 한다. (auto unboxing)
- 그런데 null을 int로 바꿀 수 없으니 NullPointerException이 터지는 것이다.
NullPointerException 피하기 위한 해결책
✅ 1. null 체크 먼저 하기
- int result = (a != null) ? (a + b) : b;
✅ 2. Optional 사용하기 (Java 8 이상)
- int result = Optional.ofNullable(a).orElse(0) + b;
✅ 3. 기본값으로 초기화하기
- Integer a = 0; // null이 아니라 0으로 시작
❔Boxing & Unboxing 성능 고려
기능적 편의성을 위해 오토 박싱 & 오토 언박싱을 제공하지만 다른 타입간의 형 변환은 애플리케이션의 성능에 영향을 미치게 된다. 애플리케이션의 성능 측면에서 봤을 때 반드시 필요한 상황이 아니라면 지양해야 하는 것이 옳다.
1️⃣ Auto Boxing 포함 연산
public static void main(String[] args) {
long t = System.currentTimeMillis(); // 현재 시간(밀리초)를 저장
Long sum = 0L; // 래퍼 객체로 오토 박싱으로 정수 값을 저장
// 백만번 도는 동안 더하기 연산
for (long i = 0; i < 1000000; i++) {
sum += i;
}
System.out.println("processing time: " + (System.currentTimeMillis() - t) + " ms") ;
}
processing time: 34 ms
2️⃣ 기본 타입 연산
public static void main(String[] args) {
long t = System.currentTimeMillis();
long sum = 0L; // 기본형 정수 타입인 long 자료형에 정수 저장
for (long i = 0; i < 1000000; i++) {
sum += i;
}
System.out.println("processing time: " + (System.currentTimeMillis() - t) + " ms") ;
}
processing time: 5 ms
100만번의 sum 연산을 통해 두 코드를 비교하면 약 5배 차이가 난다.
실제로 대용량 트래픽이 발생하는 서비스를 이용할 경우 100만건을 넘는 처리가 필요할 것이고
단지 똑같은 자료값을 저장하지만 어떤 타입으로 선언했느냐에 따라 애플리케이션의 성능 차이가 생긴다.
참고 : https://inpa.tistory.com/entry/JAVA-%E2%98%95-wrapper-class-Boxing-UnBoxing
'CS > Java' 카테고리의 다른 글
자바의 비동기 처리 (0) | 2025.04.07 |
---|---|
Error & Exception (0) | 2025.04.04 |
Mutable & Immutable (0) | 2025.03.26 |
Call by Value & Call by Reference (0) | 2025.03.24 |
Xms, Xmx (0) | 2025.03.21 |