CS 정리

Java wrapper class and caching, boxing & unboxing

문쿼리 2025. 4. 24. 00:23

1. wrapper class

기본 자료형(Primitive Type)을 객체(Reference Type) 로 감싸서 다룰 수 있는 클래스

byte -> Byte, int -> Integer, char -> Character, boolean -> Boolean 등

 

왜 필요한가?

기본 자료형을 객체로 사용해야하는 경우 필요함.

 

1. java의 많은 기능들은 객체(Object)를 통해 사용할 수 있도록 설계되어 있음.

그래서 Object의 자식이 아닌 기본 자료형을 사용할 수 없고 wrapper 를 통해 사용함.

Collections, Generic, Reflection , Annotaion 등

 

2. wrapper 는 기본 제공 기능이 있어 유용함.

equals(), parseInt(), toString(), compareTo(), Integer.MAX_VALUE 등

 

3. null 표현 가능

DB, json등과 연동 시 없는 값에 대한 표기를 유용하게 할 수 있음

 

특징

  • 불변(immutable): 한 번 생성되면 값을 바꿀 수 없다.
    변수에 새 값을 할당하면, 새 값의 주소를 참조하게되며 기존값은 참조를 잃을 뿐임
  • null 허용: 객체이기 때문에 null 값을 가질 수 있다.
  • 캐싱 처리: Integer, Byte, Short, Long, Character의 일부 값은 내부적으로 캐싱되어 효율성을 높여줌
    예를 들어 -128 ~ 127 범위의 Integer 값은 재사용
  • 성능 이슈: boxing/unboxing이 자주 발생하면 성능에 영향을 줄 수 있다. (불필요한 객체 생성)

 

2. wrapper class caching

 

작은 수의 연산이 빈번한 프로그래밍의 특성에 따라 성능적 관점에서 캐싱이 도입되어 있음-128 ~ 127 :Byte, Short, Integer, Long0~127 :Charactertrue/false :Boolean

 

그래서, 완전 캐싱인 Boolean을 제외하고는 값 비교에 유의해야함 equals() 권장

Short a = 127;
Short b = 127;
System.out.println(a == b); // true

Long x = 128L;
Long y = 128L;
System.out.println(x == y); // false
System.out.println(x.equals(y)); // true

 

 

캐싱에 의해서 wrapper의 생성에 있어서도 차이가 발생

valueOf()의 경우 캐싱이 동작하지만 new의 경우 항상 새 객체를 생성하기 때문에 valueOf()의 메모리 효율이 더 좋다.

Integer a = Integer.valueOf(100);
Integer b = Integer.valueOf(100);
System.out.println(a == b); // true (같은 캐시 객체)

Integer c = new Integer(100);
Integer d = new Integer(100);
System.out.println(c == d); // false (새 객체 각각 생성)

 

그래서 Short, Integer, Boolean, Long등의 wrapper를 만드는 경우 valueOf()를 사용하는게 좋다!

Integer i = Integer.valueOf(100); // new Interger() is deprecated
Long l = 200L; // 오토 박싱은 내부적으로 Long.valueOf(200L) 동작

 

특수한 목적을 가진 프로그래밍을 위해서 캐싱 범위를 조절할 수 있다 (써본적 없다..)

java -Djava.lang.Integer.IntegerCache.high=1000 ClassName

 

3. wrapper class boxing & unboxing

기본형 타입을 wrapper로 변경할 때(boxing), 반대로 wrapper를 기본형으로 바꿀 때(unboxing) 발생한다.

1) 값이 null인 wrapper를 기본형으로 바꾸면 nullPointerException이 발생하기 때문에 유의해야한다.

2) 반복적인 boxing/unboxing은 성능을 저하시킬 수 있다.

- 객체 생성 및 GC 비용 증가 :기본자료형은 스택, 객체는 힙에 저장되기 때문에 객체 생성 비용 및 GC 비용도 증가함

- 메서드 호출 비용 증가 :박싱은 valueOf() 메서드를 호출하기 때문에 기본형에 비해 연산 비용이 큼

 

+보너스

valueOf()와 new()를 공부하다보니 부동소수점 이슈가 생각남

double을 BigDecimal로 바꿀때 유의할 것

절대 new BigDecimal(double) 쓰면 안됨! new BigDecimal(0.1); 안티코딩

 

double을 문자열로 변경하고 쓰기 또는 valueOf() 사용하기

new BigDecimal("0.1")

BigDecimal.valueOf(0.1)