래퍼 클래스(Wrapper Class) 란?
한마디로, 기본 타입을 객체로 다룰 수 있게 해주는 클래스이다.
차근차근 설명하자면, 래퍼 클래스는 '포장지' 라는 뜻의 'Wrapper' 라는 단어의
의미에서 알 수 있듯 선물처럼 무언가를 포장하는 클래스이다.
선물은 내가 고른 물건을 이쁘게 주기 위해 포장하는데,
래퍼클래스는 정확히 무엇을, 왜, 어떻게 포장할까?
무엇을 포장할까?
자바는 기본 타입(Primitive type)과 참조 타입(Reference type)으로 나누어진다.
이 중 래퍼 클래스는 기본 타입(Primitive type)을 포장하여 객체를 만든다.
기본 타입을 왜 포장하는지 알기 전, 기본 타입과 참조 타입에 대한 이해가 필요하다.
1. 기본 타입(Primitive type)
| 타입 | 기본값 | |
| 정수형 | byte | 0 |
| short | 0 | |
| int | 0 | |
| long | 0L | |
| 실수형 | float | 0.0F |
| double | 0.0 | |
| 문자형 | char | '\u0000' |
| 논리형 | boolean | false |
기본 타입은 int, float, boolean 같이
계산을 위해 실제 값을 저장하고 연산하는 데 사용된다.
기본 타입은 다음과 같은 특징을 가지고 있다.
1. 기본값이 정해져 있어서 null 값을 가질 수 없다.
2. 저장공간에 실제 값을 저장한다.
3. 소문자로 시작된다.
4. 메모리의 스택에 저장된다.
2. 참조 타입(Reference type)
| 타입 | 기본값 |
| 배열(array) | null |
| 클래스(class) | |
| 인터페이스(interface) | |
| 열거(enum) |
참조 타입은 클래스, 배열 , 열거 타입 등
객체로 사용할 수 있는 타입을 지칭한다.
참조 타입은 다음과 같은 특징을 가지고 있다.
1. 자료가 저장된 공간의 주소를 저장한다.
2. null 값을 가질 수 있다.
3. 메모리의 힙에 실제 값을 저장하고, 주소값은 스택에 저장한다.
왜 포장할까?
각 타입의 특징에서 이유를 알 수 있는데,
래퍼 클래스는 객체를 지향하는 자바 언어에서
객체로 사용하지 못하는 기본 타입(Primitive type)을 객체로 사용하기 위해서다.
자바 프로그래밍을 하다보면 데이터를 객체 형태로 사용해야 하는 경우가 종종 있다.
1. null 값을 저장해야 할 때
만약, 데이터베이스에서 숫자 값을 가져올 때 null값이 있다면 기본 타입으로 저장할 시 오류가 날 수 있다.
이때, 래퍼 클래스를 사용하면 null값을 저장하여도 오류가 발생하지 않는다.
Integer num = null; // 래퍼클래스 - 가능
int num = null; // 기본 타입 - 불가능
2. 컬렉션 및 제네릭에서 기본 타입을 저장해야 할 때
ArrayList와 Vector같은 컬렉션은 기본 타입을 직접 저장할 수 없기 때문에 래퍼 클래스로 저장을 해야한다.
기본 타입은 메모리의 스택(stack)에 저장되는 반면, 컬렉션은 객체가 저장되어 있는 힙(heap)을 가르키기 때문이다.
그래서 래퍼클래스를 통해서만 사용할 수 있다.
// 자료형을 선언할 때 쓰이는 < > 기호가 제네릭이다. 이 괄호 안에는 객체 타입만 들어갈 수 있다.
import java.util.Vector;
import java.util.ArrayList;
public class Example {
public static void main(String[] args) {
// Vector<int> vector = new Vector<>(); // 기본 타입 - 불가능
// ArrayList<int> list = new ArrayList<>(); // 기본 타입 - 불가능
Vector<Integer> vector = new Vector<>(); // 래퍼클래스 - 가능
vector.add(10); // int -> Integer 오토박싱
vector.add(20);
ArrayList<Integer> list = new ArrayList<>(); // 래퍼클래스 - 가능
list.add(100); // int -> Integer 오토박싱
list.add(200);
System.out.println(vector.get(0));
System.out.println(list.get(0));
}
}
3. 메서드에서 객체를 인자로 받거나 리턴할 때
메서드의 매개변수나 반환값이 객체여야 하는 경우 기본 타입을 직접 사용할 수 없다.
하지만, 자바의 오토박싱(Auto-Boxing) 기능 덕분에 자동으로 래퍼 클래스로
변환되어 자연스럽게 기본 타입을 삽입할 수 있다.
// 오토박싱에 대해선 아래에서 설명
public class Example {
public static void Number(Object obj) {
System.out.println(obj);
}
public static void main(String[] args) {
Number(10); // int → Integer 변환 오토박싱 덕분에 가능
Number(3.14); // double → Double 변환 오토박싱 덕분에 가능
Number("Hello"); // String은 원래 객체라 가능
}
}
어떻게 포장할까?
위에 예시를 들 때 몇몇은 나왔지만, 각 기본 타입을 포장하기 위한 포장지(래퍼 클래스)는 다음과 같다.
| 기본 타입 | 래퍼 클래스 |
| int | Integer |
| char | Character |
| byte | Byte |
| short | Short |
| long | Long |
| float | Float |
| double | Double |
| boolean | Boolean |
거의 기본 타입에서 대문자로 조금 바뀐 정도이다.
특정 기본 타입을 객체로 만들기 위해서 해당하는 래퍼 클래스를 사용하면 된다.
Integer number = new Interger(1); // 구식 코드
Integer number = Integer.valueOf(1); // 최신 코드
// number라는 래퍼 클래스를 Integer 형식으로 생성하고 그 값을 1로 할당
이때, 기본 타입과 래퍼 클래스 간의 변환을 박싱(Boxing)과 언박싱(UnBoxing) 이라고 한다.
포장을 해버렸지만, 안에 물건을 더 넣고 싶으면 포장을 다시 뜯어야 하듯이..
객체로 만들었지만 값을 더하거나 변환 시키고 싶다면 언박싱을 해야한다.
int num = 1;
Integer number = Integer.valueOf(num); // 기본 타입 -> 래퍼클래스 | 박싱(Boxing)
num = number.intValue(); // 래퍼클래스 -> 기본 타입 | 언박싱(UnBoxing)
num = num + 1; // 물건 추가 | 값 변경
number = Integer.valueOf(num); // 기본 타입 -> 래퍼클래스 | 박싱(Boxing)
하지만, JDK 1.5 이상 버전 부터는 박싱과 언박싱을 일일이 할 필요 없이 자동으로 처리해주는
오토박싱(Auto-Boxing)과 오토언박싱(Auto-UnBoxing)을 지원한다.
// 이 기능은 큰 차이는 아니지만, 속도 면에서 좋지 못하기 때문에 무조건적인 사용은 지양하는 게 좋다.
import java.util.ArrayList;
public class Example {
public static void main(String[] args) {
int n = 100;
int m = 200;
ArrayList<Integer> list = new ArrayList<>();
list.add(n); // Integer만 더할 수 있는 ArrayList에 int를 더해도 오류 X
list.add(m); // 자바 내부에서 자동으로 박싱하여 더했기 때문이다.
int num1 = list.get(0); // 위와 같이 Integer -> int로 자동으로 언박싱하여 값을 할당했다.
int num2 = list.get(1);
System.out.println(num1); // 100
System.out.println(num2); // 200
}
}
public class Example {
public static void main(String[] args) {
Integer num1 = 1; // 오토박싱
Integer num2 = Integer.valueOf(3); // 박싱
int int1 = num1; // 오토언박싱
int int2 = num2.intValue(); // 언박싱
// 오토 언박싱하여 연산하고, 다시 오토박싱하여 저장
Integer res1 = num1 + num2;
Integer res2 = int1 - int2;
int res3 = num1 * int2;
System.out.println(res1); // 4
System.out.println(res2); // -2
System.out.println(res3); // 3
}
}
래퍼 클래스와 기본 타입의 비교
다른 비교 연산은 문제가 되지 않지만, 동등 연산에서는 문제가 생길 수도 있다.
객체에서 동등 연산자 == 은 객체의 값을 비교하는 게 아닌 객체의 주소값을 비교하기 때문이다.
Integer num1 = Integer.valueOf(10);
Integer num2 = Integer.valueOf(1000);
Integer num3 = Integer.valueOf(10);
System.out.println(num1 == num3); // false | 값이 같아도 다른 객체이기 때문에 다른 주소값.
System.out.println(num1.equals(num3)); // true | equals() 메서드를 사용하면 예상대로 출력된다.
System.out.println(num1 < num2); // true | 그 외 비교연산은 잘 출력된다.
참고문헌
https://www.geeksforgeeks.org/wrapper-classes-java/
'JAVA' 카테고리의 다른 글
| [JAVA] ORM 이란? (0) | 2025.05.31 |
|---|---|
| [JAVA] JDBC 정리 (0) | 2025.05.27 |
| [JAVA] 스레드(Thread) 정리 (0) | 2025.03.01 |
| [JAVA] 컬렉션(Collection) 정리 / Map (0) | 2025.02.27 |
| [JAVA] 컬렉션(Collection) 정리 / List, Set, Queue (0) | 2025.02.24 |