자바/객체지향 프로그래밍(OOP)

String과 래퍼 클래스의 객체생성

Blue_bull 2025. 2. 7. 01:09

String과 래퍼 클래스는 왜 객체를 생성하지 않고 사용할 수 있을까?

Java에서 String과 래퍼 클래스(Integer, Double, Boolean 등)는 객체 재사용을 위한 특별한 설계 덕분에 new 키워드를 사용하지 않고도 쉽게 사용할 수 있다. 이는 String Pool과 오토박싱 & 캐싱 기법 덕분이다.


1. String Pool (문자열 상수 풀)

String Pool은 JVM의 힙 메모리에서 특별한 영역으로, 동일한 문자열 리터럴을 공유하여 메모리를 절약하는 기법이다.

String s1 = "hello";
String s2 = "hello";
System.out.println(s1 == s2); // true (같은 객체)
  • "hello"는 String Pool에 저장되며, 동일한 문자열이 있으면 기존 객체를 재사용한다.
  • 하지만 new String("hello")를 사용하면 힙(Heap) 영역에 새로운 객체를 생성한다.
String s3 = new String("hello");
System.out.println(s1 == s3); // false (다른 객체)
  • new String("hello")는 String Pool을 사용하지 않으므로, s1과 다른 객체가 된다.
  • 그러나 intern()을 사용하면 String Pool에 추가하여 기존 객체를 재사용할 수 있다.
String s4 = new String("hello").intern();
System.out.println(s1 == s4); // true (String Pool을 참조)

2. 래퍼 클래스의 오토박싱(Auto-boxing)과 언박싱(Unboxing)

오토박싱(Auto-boxing)

자바에서는 기본형(Primitive type) 값을 래퍼 클래스 객체로 자동 변환하는 기능을 제공한다.

Integer num = 10; // 내부적으로 Integer.valueOf(10) 호출

valueOf()를 호출하여 Integer 객체로 변환됨.

언박싱(Unboxing)

래퍼 클래스 객체에서 기본형 값을 자동으로 추출하는 기능도 제공한다.

int n = num; // 내부적으로 num.intValue() 호출

intValue()를 호출하여 기본형(int)으로 변환됨.


3. 래퍼 클래스의 캐싱 (Wrapper Class Caching)

특정 범위의 값은 캐싱하여 객체를 재사용한다.
이로 인해 동일한 값을 가진 객체를 여러 번 생성하지 않고, 메모리를 절약할 수 있다.

Integer num1 = 100;
Integer num2 = 100;
System.out.println(num1 == num2); // true (같은 객체 재사용)

하지만 캐싱 범위를 벗어나면 새로운 객체를 생성한다.

Integer num3 = 200;
Integer num4 = 200;
System.out.println(num3 == num4); // false (다른 객체)

valueOf() 내부에서 -128 ~ 127 범위의 값은 캐싱되고, 그 외 값은 새로운 객체가 생성된다.

각 래퍼 클래스의 캐싱 범위

래퍼 클래스 캐싱 범위
Integer -128 ~ 127
Byte -128 ~ 127
Short -128 ~ 127
Character 0 ~ 127
Boolean true, false
Long -128 ~ 127
Double / Float ❌ 캐싱 안 함 (항상 새로운 객체 생성)

4. valueOf() vs new Integer() 차이

Integer a = Integer.valueOf(100); // 캐싱된 객체 사용
Integer b = new Integer(100); // 새로운 객체 생성
System.out.println(a == b); // false
  • Integer.valueOf(100)캐싱된 객체를 재사용하여 성능을 최적화한다.
  • new Integer(100)항상 새로운 객체를 생성하므로 비효율적이다.
  • Java 9 이후 new Integer(int) 생성자는 Deprecated(사용 비권장).

5. String과 래퍼 클래스의 차이점

구분 String 래퍼 클래스 (Integer, Double 등)
역할 문자열 저장 및 조작 기본형(Primitive type)을 객체로 감싸는 역할
불변성(Immutable) ✅ 변경 불가능 ✅ 변경 불가능
메모리 최적화 String Pool 사용 (리터럴 재사용) -128 ~ 127 범위 캐싱
기본형과 연결 ❌ 없음 (기본형이 아님) int ↔ Integer 자동 변환 (오토박싱/언박싱)
객체 생성 방식 "hello" → String Pool에서 재사용 Integer.valueOf(100) → 캐싱된 객체 사용

String은 기본형과 관련이 없지만, 래퍼 클래스는 기본형 값을 객체로 변환하는 역할을 한다.


6. 결론

  1. String은 String Pool을 사용하여 동일한 문자열을 재사용한다.
  2. 래퍼 클래스는 valueOf()를 통해 특정 범위(-128 ~ 127)의 값을 캐싱하여 객체를 재사용한다.
  3. 오토박싱(Auto-boxing)과 언박싱(Unboxing) 덕분에 new Integer(10)을 사용하지 않고도 Integer num = 10;처럼 객체를 생성할 수 있다.
  4. Double과 Float은 캐싱을 지원하지 않으며, 항상 새로운 객체가 생성된다.
  5. Java는 성능 최적화를 위해 객체 재사용 기법을 적극 활용하고 있다.

이러한 설계 덕분에 new 없이도 String과 래퍼 클래스 객체를 사용할 수 있다!