본문 바로가기

Java

Java String이란? (StringBuilder, StringBuffer, String Iterning, String pool)

Java String

평소에 가장 많이 쓰는 타입 중 하나인 String에 대해 자세히 알고 있지 못했다. String의 특징에 대해 살펴보고 이를 보완하기 위해 나온 JVM에서 제공하는 메모리 관리와 여러 다른 객체들을 살펴보자.

 

String 객체의 특징

String의 가장 큰 특징으로는 불변성(Immutability)을 꼽을 수 있다.

 

String text = "abcd";
textAppend = text + "efg";

 

위와 같은 코드를 작성했을 때 JVM 메모리의 변화를 예상해보자. String은 Heap 메모리에 저장되므로 Heap에 "abcd" 가 저장된 후에 "abcd" 뒤에 "efg" 가 붙어서 저장 될 것이라고 예상할 수 있을 것이다.
그러나 String은 불변성이라는 특징을 갖고 있기 때문에 "abcd" 가 저장된 메모리는 그대로 두고 문자열 "abcdefg"가 메모리에 새롭게 할당된다.
이러한 Java String의 특성은 동시성(Thread-safe)을 보장하는 장점이 있지만 메모리를 많이 차지하는 단점이 생긴다. 이러한 메모리 문제를 해결하기 위해 새로운 객체 두 가지를 제공한다.

 

StringBuffer & StringBuilder

  • 두 객체 모두 String과 달리 가변적(mutable)인 객체이다.
  • 따라서 문자열 연산 시에 객체를 새롭게 생성하지 않고 처음에 만든 객체를 이용해 변경한다.
  • 문자열 연산이 자주 발생할 때 성능적으로 유리하다.
  • StringBuilder와 StringBuffer의 차이점은 Thread-Safe 여부이다.
  • StringBuilder는 Thread-Safe하지 않고 그렇지만 동시성을 고려하지 않은(단일 쓰레드) 환경에서는 좋은 성능을 발휘한다.
  • StirngBuffer는 Thread-Safe하다. 멀티 쓰레드 환경에서 적합하다.

위의 두 객체는 String이 불변하다는 특성 때문에 발생하는 메모리 문제를 해결하기 위해 만들어진 객체이다. String이 매번 새롭게 생성되는 문제를 해결하기 위해 JVM의 메모리 레벨에서 지원하는 기술을 살펴보자.

 

String pool (String contant pool) & String interning

 

String test = "hello";
String test2 = "hello";
String test3 = new String("hello");

// 참고로 isSameAs는 == 연산으로 같은지 확인한다.
assertThat(test).isSameAs(test2);
assertThat(test).isNotSameAs(test3);
assertThat(test).isSameAs(test3.intern());

 

 

위의 코드를 봤을 때 test, test2 는 literal 방식으로 String을 생성하고, test3은 new 생성자로 String 객체를 생성하고 있다. 위와 같은 방식으로 생성했을 때의 차이점은 test, test2는 Heap 영역의 String pool에 저장되고 test3은 다른 인스턴스와 마찬가지로 Heap영역에 저장되게 된다.

  • 그럼 test == test2는 어떻게 같을 수 있을까?
    • 바로 String pool에서 같은 문자열에 대해서는 하나의 문자열만 저장하는 방식을 사용한다. 이를 String interning이라고도 한다.
    • 내부적으로 hashmap을 사용해서 문자열을 저장한다.
    • 명시적으로 intern()이라는 메서드를 사용해서 풀에 저장하도록 할 수 있다.

Reference