이번 글은 Wrapper Class에 대한 개념과 사용 이유에 대해 정리해 보려고 합니다. 'wrapper'라는 말의 의미는 '감싸다' 라는 뜻으로 랩으로 음식을 감싸는 것을 연상할 수 있습니다.
그럼 이제 궁굼한건 "뭘 감싸는 거지?" 라는 물음이 생기실 겁니다. 결론적으로 말하자면 Primitive type 변수를 감싸는 겁니다.
그럼 이어서 'Primitive type 변수'는 뭔지에 대한 물음이 생기실 겁니다. Wrapp Class에 대한 자세한 내용을 알기 전에 Primitive type에 대한 개념 정리를 먼저 하겠습니다.
1. 자바의 데이터 타입의 종류
자바에서는 데이터 타입이 크게 두가지, 원시타입(Primitive type)과 참조타입(Reference Type) 이 있습니다.
- 원시 타입은 정수, 실수, 문자, 논리형 의 실제 데이 값을 저장하는 타입입니다.
- 참조타입은 객체의 번지를 참조 (주소를 저장) 하는 타입으로 메모리 번지 값을 통해 객체를 참조하는 타입입니다.
1-1. 원시타입 (Primitive Type)
실제 값 만을 저장하는 공간으로 스택 메모리 영역에 저장됩니다.
기본값이 있기 때문에 Null이 존재 하지 않고 만약 기본형 타입에 Null을 넣고 싶다면 래퍼 클래스를 활용합니다.
타입 | 할당되는 메모리 크기 | 기본값 | |
논리형 | boolean | 1 byte | false |
정수형 | byte | 1 byte | 0 |
short | 2 byte | 0 | |
int | 4 byte | 0 | |
long | 8 byte | 0L | |
실수형 | float | 4 byte | 0.0F |
double | 8 byte | 0.0 | |
문자형 | char | 2 byte | '\u0000' |
1-2. 참조타입 (Reference Type)
스택에 저장되어 있는 실제 값의 주소를 저장하는 곳으로 힙 메모리 영역에 저장됩니다.
예시 | 기본값 | 할당되는 메모리 크기 | |
배열(Array) | new 를 사용해 생성된 객체 | Null | 4 byte (객체의 주소값 != 실제 값의 주소값이 아닌 객체 자체에 대한 주소값) |
열거(Enum) | |||
클래스(Class) | |||
인터페이스(Interface) |
둘의 기본 개념과 정의는 이정도 이고 그림을 통해서 이해해 보겠습니다.
예를 들어 원천 타입인 int, double type 변수는 stack 영역에 저장되어 있고 참조 타입은 Class Test 객체는 heap 영역에 저장되어 있습니다. Primitive type 은 모두 스택에 그외 static 이 붙지 않은 건 다 heap에 저장된다. 변수에 static이 붙는 경우는 static 영역에 저장됩니다. 그럼 이제 본론으로 돌아와서 오늘의 주제인 Wrapper Class 에 대해 정리하겠습니다.
2. Wrapper Class 이란?
Wrapper Class 는 자바에서 사용되는 원천타입의 데이터를 서로 형 변환이 가능하도록 지원해 주는 Class로써, 원찬타입의 자료형들을 Class화 한 것입니다. 정리하자면 아래 표와 같습니다.
원천타입 | Wrapper Class |
int | Integer |
byte | Byte |
char | Charcter |
double | Double |
float | Float |
long | Long |
short | Short |
3. Wrapper Class 를 사용하는 이유
Wrapper Class 를 사용하는 이유는 크게 두 가지로 형변환과 비교연산을 하기 위해서 입니다. 먼저 형변환이라는 건 아래의 코드 예시처럼 데이터 타입을 변환하는 것을 의미합니다.
int value = 10; Integer wrapper_value = new Integer(value); byte byte_value = wrapper_value.byteValue(); short short_value = wrapper_value.shortValue();
다음은 비교연산을 위한 예제를 보겠습니다.
int value = 10; Integer wrapper_value = new Integer(value); Integer wrapper_value2 = new Integer(value); System.out.println(wrapper_value == wrapper_value2); System.out.println(wrapper_value.equals(wrapper_value));
둘 다 true가 찍힐 것 같았는데..
false true
안되네요..? 왜 안되는지 알기 위해서는 Auto Boxing과 Auto unBoxing의 개념을 알고 있어야 합니다.
4. Auto Boxing 과 Auto UnBoxing
먼저 Boxing이란 '상자에 넣는다'는 것을 의미한다. 여기서 박스는 위 그림에서 Integer(Class) 객체를 의미하는데 Class내부에는 멤버변수, 메서드, 생성자등 다양한 요소가 존재하는데 거기서 int type의 변수를 포함시켜 Integer 객체로 만든다고 생각하면 될 것 같습니다.
때문에 엄밀히 말하자면
int value = 10; Integer wrapper_value = new Integer(value);
두개는 모두 10이라는 같은 값을 갖지만 두 개가 같다고는 할 수 없다고 이해하시면 될 것 같습니다. unBoxing이란 반대로 '상자에서 꺼낸다'는 의미입니다. 즉, Integer 객체 내에서 int 형 타입의 변숫값만 뽑아낸다는 걸로 이해하시면 될 것 같습니다.
그럼 Auto Boxing 과 Auto unBoxing은 Boxing과 unBoxing을 자동으로 해준다는 의미인데 예를 들자면,
int value = 10; Integer wrapper_value = new Integer(value); System.out.println(wrapper_value == value);
두 개의 값은 엄밀히 말하자면 아까는 다르다고 했으니까 결괏값은 false가 나와야 합니다.
ture
왜 안돼... 라고 생각하지 마시고 여기서 등장하는 개념이 auto unBoxing입니다. 자바 내에서 자동으로 unBoxing 해줘서 값을 비교하기 때문에 true값이 나오게 되는 겁니다.
하지만 Auto Boxing 과 Auto unBoxing을 자주 사용하는 것 은 좋지 않습니다. 객체와 변수의 의미를 명확히 하는 것이 OOP적 관점에서 매우 중요하기도 하고 코드에 대한 이해도가 낮아질 수 있기 때문입니다. 마지막으로 하나만 더 짚고 넘어갈 게 있습니다.
"Wrapper Class 는 Call by Value일가 Call by reference일까?"
Call by Value 와 Call by reference에 대한 개념은 아래의 링크에서 확인하실 수 있습니다.
결론부터 말하자면 Wrapper Class는 클래스임에도 불구하고 Primitive type처럼 Call by Value로 작동하는데 그 이유는 auto unBoxing 때문입니다. Wrapper Class는 Call by Value로 작동하기 때문에 주의하시면 될 것 같습니다.
자세한 이유에 대한 설명은 아래 링크를 참고해 주세요!
정리하자면
1. 자바의 데이터 타입은 원천타입과 참조타입이 존재한다.
2. Wrapper Class 의 목적은 형변환과 비교연산이다.
3. Auto Boxing , Auto unBoxing 은 가급적 사용을 지양해야 한다.
4. Wrapper Class는 Call by Value로 작동한다.
'Language > Java' 카테고리의 다른 글
추상 (Abstract) 클래스 와 인터페이스 (Interface)의 사용 목적과 차이점 (0) | 2022.01.10 |
---|---|
Exception (예외) 의 개념과 사용 이유 (0) | 2022.01.07 |
static의 사용 이유와 스레드(thread)의 대한 개념 (0) | 2022.01.06 |
Overriding (오버라이딩) 과 Overloading (오버로딩) (0) | 2022.01.06 |
Call by reference 와 Call by Value 차이 (0) | 2022.01.05 |