Wrapper Class란?
Java에서 데이터 타입은 크게 기본형(primitive type)와 참조형(reference type)으로 나뉜다.
기본형은 int, char, boolean, float 등이 있고, 참조형은 기본형을 제외한 모든 타입을 말한다.
Wrapper Class는 기본형에 이것저것 기능을 추가해서 포장한 객체다.
“객체로 포장했다”는 의미는 단순한 기본형을 버라이어티하고 so easy~ 하게 사용할 수 있다는 뜻!
먼저, Wrapper Class 종류부터 차근차근 알아보자.
Wrapper Class 종류
기본타입 | 래퍼 클래스 |
byte | Byte |
short | Short |
int | Integer |
long | Long |
float | Float |
double | Double |
char | Character |
boolean | Boolean |
Java Wrapper Class 종류다. 모든 기본형에 대응해서 제공한다.
또한, Wrapper Class 모두 java.lang 패키지에 포함되어있다.
아래 링크에서 java.lang 패키지에 대한 내용을 확인 할 수 있다.👇
Wrapper Class 맛보기
Integer i = Integer.valueOf(20); // Integer Wrapper Class 생성
Integer i = new Integer(20); // java9 버전부터 Deprecated 됨!
- int 기본형을 다루는 Integer Wrapper Class 생성방법이다.
- new Integer()로 생성하는 방법은 Deprecated되었다.
Integer i1 = Integer.valueOf(20);
int compare = i1.compareTo(10);
System.out.println(compare); // 1 출력
- Integer compareTo()를 사용해서 숫자를 비교 해보자.
- 비교대상보다 크면 1, 작으면 -1, 같으면 0을 반환한다.
- Wrapper Class가 없다면 한땀한땀 직접 compareTo()를 구현해야된다. 귀찮귀찮~
String numString = "1";
int num = Integer.parseInt(numString);
System.out.println(num); // 1
- 문자열 “1”을 숫자타입으로 변경해보자.
- Integer parseInt() 를 사용하면 so easy~ 하게 변경할 수 있다.
간단하게 Wrapper Class 맛보기를 해봤다.
Wrapper Class에서 제공하는 다양한 메서드는 다음에 따로 한번 다뤄보겠다.
앞서 말했듯 “Wrapper Class는 기본형에 이것저것 기능을 추가해서 포장한 객체다.”
왜 이것저것 넣어서 객체로 포장했을까?
Wrapper Class를 왜?!
편리한 기본형 핸들링
compareTo(), parseInt() 와 같은 메서드를 통해 기본형을 더욱 간편하게 다룰 수 있기 때문!
우리가 배열보다 List를 사용하는 가장 큰 이유가 무엇일까!?
배열은 정적 크기를 가진다.
배열 크기를 증가시키려면 새로운 배열을 생성하고 기존 배열 요소를 복사해야 한다. 😫
반면, List의 경우 동적 크기를 가진다.
내부적으로는 새로운 배열을 생성하고 요소를 복사하는 작업을 수행하지만, 사용자는 이를 신경 쓸 필요 없이 편하게 사용하면 된다. so cool편함 😎
Wrapper Class도 마찬가지다.
기본형을 객체로 감싸서 다양한 기능을 제공하고, 개발자는 제공된 기능을 편리하게 사용하면된다.
컬렉션, 제네릭에 사용
// 컬렉션
List<Integer> intList = new ArrayList<>();
intList.add(10);
List<int> intList = new ArrayList<>(); // 컴파일 에러
// 제네릭
class Superpil<T> {
private T value;
public void set(T value) { this.value = value; }
public T get() { return value; }
}
Superpil<Integer> superpil = new Superpil<>();
superpil.set(10);
자바에서 컬렉션과 제네릭은 기본형을 직접적으로 사용할 수 없다.
기본형을 사용하려면 Wrapper Class를 이용해야 한다.
Wrapper Class의 존재 이유를 알았으니, 이제 조금 더 심도 있게 파헤쳐보자.
박싱(Boxing) & 언박싱(Unboxing)
Wrapper Class에 박싱(Boxing)과 언박싱(Unboxing) 개념이 있다.
기본형을 Wrapper Class로 변환하면 박싱(Boxing).
Wrapper Class를 기본형으로 변환하면 언박싱(UnBoxing).
박싱(Boxing)
int num = 10;
Integer box = Integer.valueOf(num);
- 기본형을 Wrapper Class로 변환
언박싱(Unboxing)
Integer box = Integer.valueOf(10);
int unBox = box.intValue();
- Wrapper Class를 기본형으로 변환
바쁘다 바뻐.. 현대사회에서 매번 이렇게 박싱, 언박싱하기 귀찮다. 🤯
그래서 자바는 개발자를 위해 자동 박싱, 언박싱을 지원한다.
자동 박싱(Auto Boxing) & 자동 언박싱(Auto UnBoxing)
자동 박싱과 자동 언박싱은 개발자가 명시적으로 박싱과 언박싱을 수행하지 않아도, 컴파일러가 자동으로 변환해준다.
자동 박싱(Auto Boxing)
int num = 10;
Integer autoBox = num; // 자동으로 Integer.valueOf(num) 호출
- valueOf() 없이 자동으로 박싱
자동 언박싱(Auto UnBoxing)
Integer box = Integer.valueOf(10);
int autoUnBox = box; // 자동으로 intValue() 호출
- intValue() 없이 자동으로 언박싱
Wrapper Class 특징
동등성, 동일성 비교
Integer a = new Integer(100);
Integer b = new Integer(100);
System.out.println(a == b); // false
System.out.println(a.equals(b)); // true
- Wrapper Class 객체를 비교할 때는 == 연산자 대신 equals 메서드를 사용해야 한다.
- == 연산자는 객체 참조값을 비교하지만, equals 메서드는 객체의 값을 비교한다.
- 참고로, new 키워드를 사용한 객체 생성 방식은 Deprecated되었다.
문자열처럼 풀(Pool)
Wrapper Class는 문자열처럼 특정 값에 대해 객체를 재사용하기 위해 풀(Pool)을 가지고 있다.
자주 사용되는 값에 대해 새로운 객체를 생성하지 않고 기존 객체를 재사용함으로써 메모리 낭비를 줄일 수 있다. 다음 예제를 보자.
Integer integer1 = 10;
Integer integer2 = 10;
System.out.println(integer1 == integer2); // true
- 동일한 값을 가진 객체가 동일한 참조값을 가진다.
- 즉, 자바는 숫자 10에 대해 객체를 메모리에 생성하고, integer1에 그 객체의 참조값을 할당한다.
- 이후, integer2도 숫자 10을 할당 할 때, 이미 캐싱된 객체가 존재하므로, integer2에도 integer1과 동일한 참조값이 할당된다.
Integer integer1 = 1;
Integer integer2 = Integer.valueOf(1);
System.out.println("integer1 == integer2 : " + (integer1 == integer2)); // true
Integer integer3 = new Integer(1);
System.out.println("integer1 == integer3 : " + (integer1 == integer3)); // false
System.out.println("integer2 == integer3 : " + (integer2 == integer3)); // false
- valueOf() 메서드를 사용하면 자바는 동일한 값을 가진 기존 객체를 재사용한다.
- 따라서 integer1과 integer2는 동일한 객체를 참조하게 되어, 참조값이 같다.
- 반면, new 키워드로 래퍼 클래스를 생성하면, 메모리에 항상 새로운 객체를 생성한다. 기존 객체와 참조값이 다르다.
불변성
Wrapper Class는 불변 객체(immutable object) 특징을 가진다.
예전 글에서 불변 객체를 심도있게 파헤쳐봤다. 아래 링크를 클릭해서 불변 객체에 대해 빠르게 알아보자.
// java 21 기준
public final class Integer extends Number implements Comparable<Integer>, Constable, ConstantDesc {
private final int value;
@IntrinsicCandidate
public static Integer valueOf(int i) {
if (i >= IntegerCache.low && i <= IntegerCache.high)
return IntegerCache.cache[i + (-IntegerCache.low)];
return new Integer(i);
}
@Deprecated(since="9", forRemoval = true)
public Integer(int value) {
this.value = value;
}
}
- 대표적으로 Integer 클래스 내부를 살펴보자.
- 클래스에 final을 선언하여 상속할 수 없도록 했다. 필드도 private final로 선언하여 한 번 생성된 후에는 변경이 불가능하다.
- Integer 객체를 생성할 때 값을 받아 value에 할당한다. 이 값은 객체가 생성된 이후에는 변경할 수 없다.
Integer superpil = 100;
System.out.println(System.identityHashCode(superpil)); // 주소값 361174851
superpil = 200;
System.out.println(System.identityHashCode(superpil)); // 주소값 1067040082
- 처음 superpil 변수에 100을 할당해서 초기화했다.
- 다음 superpil 변수에 200을 재할당하면 Integer에 value값이 변경되지 않고 새로운 Integer 객체가 생성되어 할당된다.
- 각각 주소값을 조회하면 다르게 출력된다.
- 정리해보면, 처음에 superpil 변수에 값 100을 할당해서 초기화하고, superpil 변수에 값 200을 재할당하면 Integer 객체의 value 값이 변경되는 것이 아니라, 새로운 Integer 객체가 생성되어 superpil 변수가 이 새로운 객체를 참조하게 된다. 그 결과, superpil의 메모리 주소값이 달라진다.
Null값 허용
Integer myNameIsInteger = null;
Boolean myNameIsBoolean = null;
Long myNameIsLong = null;
Character myNameIsCharacter = null;
int num = null; // 컴파일 에러
boolean trueFalse = null; // 컴파일 에러
long longNum = null; // 컴파일 에러
char ch = null; // 컴파일 에러
- Wrapper Class는 객체다. 당연하게 null값을 가질 수 있다.
- 언제라도 NullPointerException을 만날 수 있다는 이야기! 조심조심!
정리
이 글에서는 Java Wrapper Class를 살펴봤다. 마지막 정리 해보자.
Wrapper Class는 기본형을 객체로 감싸 다양한 기능을 제공하며, 컬렉션과 제네릭에서 기본형을 사용할 수 있게 한다.
또한, 박싱(Boxing)과 언박싱(Unboxing)을 통해 기본형과 Wrapper Class 간의 자동 변환을 지원한다.
Wrapper Class 동등성, 동일성 비교와 다양한 특징까지 알아봤다.
지금까지 주니어개발자의 성장기였습니다.
댓글로 부족한 내용이나 공유하고 싶은 의견을 채워주세요! 😄
'개발노트 > Java' 카테고리의 다른 글
[Java Immutable Object] 불변 객체 파헤치기 (0) | 2024.05.20 |
---|---|
[Java Basic] 자바 표준 라이브러리 소개 (0) | 2024.05.14 |
[Java Final] 키워드 파헤치기 (0) | 2024.05.09 |
[Java 초급] Overloading - 오버로딩 (0) | 2020.08.25 |
개발 기록
포스팅이 좋았다면 "좋아요❤️" 또는 "구독👍🏻" 해주세요!