Wrapper 클래스
자바에는 기본 타입과 Wrapper 클래스가 존재한다. 기본 타입(Primitive type)을 객체로 다루기 위해서 사용하는 클래스들을 래퍼 클래스(Wrapper class)라고 한다.
- 기본형 타입 : int, long, float, double, boolean 등
- Wrapper 클래스 : Integer, Long, Float, Double, Boolean 등
근데 기본형이 있는데 왜 래퍼 클래스라는 것을 만들어 굳이 객체화시키는 것일까?
자바는 객체지향언어이며, 객체가 중심으로 개발이 이루어진다. 그런데 자바 안에서 객체가 아닌 것들이 있는다. 바로 기본형(Primitive Type)이다.
기본형에 경우 객체가 아니기 때문에 다음과 같은 한계를 지닌다.
- 객체가 아니기 때문에 객체 지향 프로그래밍에 장점을 살릴 수 없다. 예를 들어 객체는 유용한 메서드를 제공할 수 있는데, 기본형에 경우 객체가 아니므로 메서드를 제공할 수 없다.
- `null`값을 가질 수 없다. 프로그래밍을 하다 보면 때로는 데이터가 `없음`이라는 상태를 나타내야 할 필요가 있다. 하지만 기본형은 값이 없을 경우 기본 값(Defalut)을 가지기 때문에 `데이터 없음`을 표현을 수 없다.
- 그 외에도 객체 참조가 필요한 컬렉션 프레임워크를 사용할 수 없으며, 제네릭도 활용할 수 없다.
정리하자면, 이러한 한계를 극복하기 위해 자바에선 기본형 타입에 객체버전인 래퍼 클래스를 제공하게 된다.
래퍼 클래스의 특정
래퍼 클래스에 경우 앞 서 포스팅했던 String 클래스와 마찬가지로 불변 객체이고, `equals`로 비교해야한다. 다음 코드에서 `==`비교가 `false`가 나오는 것은 어떻게 보면 당연하다. `newInteger`와 `integerObj`는 서로 다른 객체를 선언하였기 때문에 참조 값 자체를 비교하는 동일성 비교는 당연히 `false`가 나온다.
`equals()`의 경우 래퍼클래스에서 내부의 값을 비교하도록 재정의가 되어있으므로 `true`값이 나온다.
package lang.wrapper;
public class WrapperClassMain {
public static void main(String[] args) {
Integer newInteger = new Integer(10);
Integer integerObj = Integer.valueOf(10);
System.out.println("비교");
System.out.println("==: " + (newInteger == integerObj)); // false
System.out.println("equals: " + newInteger.equals(integerObj)); // true
}
}
박싱과 언박싱
박싱과 언박싱에 대한 개념을 먼저 살펴보자.
- 박싱 : 기본 타입 데이터에 대응하는 Wrapper 클래스로 만드는 동작
- 언박싱 : Wrapper 클래스에서 기본 타입으로 변환
// 박싱
int i = 10;
Integer num = Integer.valueOf(i);
// 언박싱
Integer num = Integer.valueOf(10);
int i = num.intValue();
참고로 `new Integer()`에 경우 deprecated 되었기 때문에 작동은 되지만, 향후 자바에서 삭제될 예정이다.
그렇기 때문에 `Integer.valueOf()`를 사용하는 걸 권장한다.
추가로 `Integer.valueOf()`에 경우 일부 성능 최적화 기능이 있다. 개발자들이 일반적으로 자주 사용하는 -128 ~ 127 범위의 `Integer` 클래스를 미리 생성해 준다. 해당 범위의 값을 조회하면 미리 생성된 `Integer` 객체를 반 환한다.
해당 범위의 값이 없으면 `new Integer()` 를 호출한다.
오토 박싱과 오토 언빅싱
JDK 1.5부터는 박싱과 언박싱이 필요한 상황에 자바 컴파일러가 자동으로 처리해 준다.
자동화된 박싱과 언박싱을 오토 박싱(AutoBoxing)과 오토 언박싱(AutoUnBoxing)이라고 부른다.
// 오토 박싱
int i = 10;
Integer num = i;
// 오토 언박싱
Integer num = Integer.valueOf(10);
int i = num;
성능
이런 오토 박싱과 오토 언박싱에 경우 성능에 대한 이슈가 발생할 수 있다.
래퍼 클래스(오버 박싱 연산)
public static void main(String[] args) {
int iterations = 1_000_000_000; // 반복 횟수 설정, 10억
long t = System.currentTimeMillis();
Long sumWrapper = 0L;
for (int i = 0; i < iterations;; i++) {
sumWrapper += i;
}
System.out.println("실행 시간: " + (System.currentTimeMillis() - t) + " ms");
}
// 실행 시간 : 1454ms
기본형 연산(동일 박싱 연산)
public static void main(String[] args) {
int iterations = 1_000_000_000; // 반복 횟수 설정, 10억
long t = System.currentTimeMillis();
long sumPrimitive = 0L;
for (int i = 0; i < iterations;; i++) {
sumPrimitive += i;
}
System.out.println("실행 시간: " + (System.currentTimeMillis() - t) + " ms");
}
// 실행 시간 : 318ms
결과
두 코드의 결과를 보면 기본형 연산이 래퍼 클래스보다 대락 5배 정도 빠른 것을 확인할 수 있다. (물론 환경에 따라 차이가 날 수 있다.)
기본형은 메모리에서 단순히 그 크기만큼의 공간을 차지한다. 예를 들어 `int` 는 보통 4바이트의 메모리를 사용한다. 래퍼 클래스의 인스턴스는 내부에 필드로 가지고 있는 기본형의 값뿐만 아니라 자바에서 객체 자체를 다루는데 필요한 객체 메타데이터를 포함하므로 더 많은 메모리를 사용한다. 자바 버전과 시스템마다 다르지만 대략 8~16 바이트의 메모리를 추가로 사용한다.
기본형과 래퍼형 성능을 고려한 개발?
두 연산은 0.3초와 1.5초의 차이를 발생하며, 이건 무려 5배의 차이를 발생시킨다. 하지만 여기서 주의할 점이 10억 번 로직을 실행했다는 것이다.
이걸 기본형이든, 래퍼 클래스든 1회로 환산한다면 둘 다 매우 빠르게 연산이 수행되며, 일반적인 애플리케이션 관점에선 이런 부분에 대한 최적화를 타이트하게 하는 것은 크게 차이를 못 느낄 가능성이 크다.
그렇기 때문에, 배치 프로그램과 같이 동일 연산이 아주 많이 수행하는 특수한 경우 거나, 수만 ~ 수십만 이상의 연산을 수행하는 경우가 아니라면 최적화를 고려할 필요까지 없다.
나 같은 경우에도 개발 경력동안 래퍼클래스에 대한 최적화를 고민해 본 적이 없다. 아무래도 한 번에 수만, 수십만 이상의 로직이 반복 수행되는 서비스나 배치 프로그램을 만든 경험이 없기 때문이다.
이 글을 쓰기 위해 참고한 김영한 님 자바 강의에서도 우선 최적화보단 유지보수하기 좋은 코드를 먼저 고민하여 거기에 맞는 코드를 작성하기를 권장한다. 최적화가 우선 시 되면 아무래도 코드가 복잡해지고, 많은 코드가 추가될 가능성이 크다. 이러면 자연스럽게 유지보수는 어려워지게 된다.
유지보수 관점에서 우선 개발을 하고 이후 성능 테스트를 해보고 문제가 되는 지점에 대해서 최적화하는 것이 아무래도 시간적인 관점에서 더 좋을 것 같다.
하지만, 래퍼 클래스에서 발생할 수 있는 성능 이슈 등을 알고 있어야 이후에 최적화를 할 수 있으니 잘 알아두도록 하자.!!
참고
김영한의 실전 자바 - 중급 1편 강의 | 김영한 - 인프런
김영한 | 실무에 필요한 자바의 다양한 중급 기능을 예제 코드로 깊이있게 학습합니다., 국내 개발 분야 누적 수강생 1위, 제대로 만든 김영한의 실전 자바[사진][임베딩 영상]단순히 자바 문법을
www.inflearn.com
'Language > Java' 카테고리의 다른 글
[Java] Class 클래스 (0) | 2025.01.30 |
---|---|
[Java] 클래스 로더 (Class Loader)와 로딩 과정 (1) | 2025.01.29 |
[Java] 불변객체 - String과 성능(StirngBuilder vs StringBuffer) (1) | 2025.01.22 |
[Java] 불변객체(Immutable Object) (0) | 2025.01.22 |
[Java] 자바의 동등성과 동일성 (==, equals(), hashcode()) (0) | 2025.01.17 |