자바의 모든 데이터 타입은 크게 2가지로 나뉜다. 이 구분은 데이터를 저장하고 다루는 방식, 즉 메모리 작동 원리와 직접적으로 연결된다.
원시 타입 (Primitive Type)
- 값을 직접 저장 : 변수가 곧 실제 데이터를 담고 있다.
- 빠른 처리 : 스택 영역에서 저장되므로, 메모리에 접근하는 속도가 매우 빠르다.
- 8가지 종류 : 자바에는 오직 8가지 원시 타입이 존재한다.
- 정수형 : `byte` , `short` , `int` ,`long`
- 실수형 : `float` , `double`
- 논리형 : `boolean`
- 문자형 : `char`
원시 타입의 메모리 작동 원리
int a = 10;
int b = a; // a의 값(10)을 복사하여 b에 저장
b = 20; // b의 값만 20으로 변경
// a는 여전히 10
위 코드에서 a와 b는 스택 메모리 내의 완전히 별개의 공간에 10이라는 값을 저장한다. b의 값을 변경해도 a의 값은 전혀 영향을 미치지 않는다.
참조 타입 (Reference Type)
- 주소(참조) 저장 : 스택에는 객체가 저장된 힙 메모리 주소만 저장하고, 실제 데이터는 힙(Heap) 영역에 저장된다.
- 객체 지향 : 클래스를 기반으로 객체를 생성하며, 자바의 모든 객체 지향적 특성(상속, 다형성 등)은 참조 타입 위에서 작동한다.
- NULL 허용 : 참조하는 객체가 없음을 의미하는 `null` 값을 가질 수 있다.
참조 타입의 메모리 작동 원리
class Data {
int value = 10;
}
Data d1 = new Data();
Data d2 = d1; // d1이 가진 '주소'를 d2에 복사
d2.value = 20;
// d1.value도 20으로 변경됨
d1과 d2는 스택에 저장되지만, 동일한 힙 영역의 객체 주소를 가리킨다. 따라서 d2를 통해 객체의 내용을 변경하면, d1이 접근하는 객체의 내용도 같이 변경된다.
Wrapper Class (래퍼 클래스)
자바의 8가지 원시 타입을 객체(참조 타입)으로 감싸서 다룰 수 있도록 만든 클래스이다.
사용하는 이유
1) 객체 지향 일관성 : 자바는 객체 지향 언어이지만, 성능을 위해 원시 타입을 사용한다. 래퍼 클래스는 필요할 때 원시 데이터를 객체로 변환하여 객체 지향적인 처리를 가능하게 한다.
2) 컬렉션 사용 : 자바 컬렉션 프레임워크 (ArrayList, HashMap)는 오직 객체(참조 타입)만 저장할 수 있다. 원시 타입의 데이터를 컬렉션에 저장하려면 래퍼 클래스를 사용해야 한다.
3) NULL 값 처리 : 원시 타입은 null을 가질 수 없지만, 래퍼 클래스는 참조 타입이므로 null 값을 가질 수 있다.
| 원시타입 (Primitive Type) | 래퍼 클래스 (Wrapper Class) |
| boolean | Boolean |
| char | Char |
| byte | Byte |
| short | Short |
| int | Integer |
| long | Long |
| float | Float |
| double | Double |
✅ 박싱 (Boxing)
박싱은 원시 타입의 값을 래퍼 클래스의 객체로 변환하는 과정을 의미한다.
- 변환 방향 : int, double 등 -> Integer, Double 등
- 전통적인 방식 : new 연산자를 사용하거나 래퍼 클래스의 정적 메서드 `valueOf()`를 사용한다.
// 원시 타입 값
int primitiveValue = 10;
// new 연산자를 이용한 박싱 (JDK 9부터 권장되지 않음)
Integer wrapperObject1 = new Integer(primitiveValue);
// valueOf() 메서드를 이용한 박싱 (일반적으로 권장)
Integer wrapperObject2 = Integer.valueOf(primitiveValue);
✅ 언박싱 (Unboxing)
언박싱은 래퍼 클래스 객체에 담긴 값을 다시 원시 타입으로 꺼내는 과정을 의미한다.
- 변환 방향 : Integer, Double 등 -> int, double 등
- 전통적인 방식 : 래퍼 클래스가 제공하는 `xxValue()` 메서드를 사용한다.
// 래퍼 클래스 객체
Integer wrapperObject = new Integer(20);
// 언박싱: intValue() 메서드를 사용
int primitiveValue = wrapperObject.intValue(); // primitiveValue는 20
✅ 오토 박싱/ 오토 언박싱 (Auto-Boxing/Auto-Unboxing)
JDK 1.5부터 자바는 개발자의 편의를 위해 박싱과 언박싱 과정을 자동으로 처리해주는 기능을 도입했다.
1) 오토 박싱 (Auto-Boxing)
컴파일러가 원시타입이 필요할 때 자동으로 래퍼 클래스 객체로 변환해주는 기능이다.
int a = 50;
Integer b = a; // 컴파일러가 Integer.valueOf(a)로 자동 변환 -> 오토 박싱
2) 오토 언박싱 (Auto-Unboxing)
컴파일러가 래퍼 클래스 객체가 필요할 때 자동으로 원시 타입 값으로 변환해주는 기능이다.
Integer c = 100;
int d = c; // 컴파일러가 c.intValue()로 자동 변환 -> 오토 언박싱
int result = c + 10; // 연산 시에도 자동으로 언박싱되어 사용됨
⚠️ 래퍼 클래스 사용 시 주의사항
오토 박싱/언박싱 덕분에 사용은 편리해졌지만, 래퍼 클래스가 참조 타입이라는 사실을 잊으면 안된다.
1) `null` 값 처리 (NullPointerException)
래퍼 클래스 객체가 null인데 이름 오토 언박싱 하려 하면 `NullPointerException`이 발생한다.
Integer myInteger = null;
int myInt = myInteger; // 여기서 NullPointerException 발생!
// (null).intValue()를 시도하는 것과 같음
2) 객체 비교 (`==` vs. `.equals()`)
래퍼 클래스는 객체이므로, `==` 연산자는 값이 아닌 주소(참조)를 비교한다. 반드시 값을 비교할 때는 `.equals()` 메서드를 사용해야 한다.
Integer obj1 = new Integer(1200);
Integer obj2 = new Integer(1200);
System.out.println(obj1 == obj2); // false (주소 다름)
System.out.println(obj1.equals(obj2)); // true (값 같음)'Java' 카테고리의 다른 글
| [Java] JVM(자바 가상 머신)에 대한 모든 것 (0) | 2025.11.10 |
|---|---|
| [Java] 자바 변수 4가지 정리 (전역, 지역, 정적, 멤버 변수) (0) | 2025.11.10 |
| [Java] 스트림(Stream)에 대하여 (0) | 2025.10.14 |
| [Java] 실수를 나타내는 Double, double, float, decimal 의 차이 (0) | 2025.10.13 |
| [Java] POJO(Plain Old Java Object) (0) | 2025.09.16 |
