[Java] 문자열(String)

Java 문자열 String

java.lang.String

Java에서 문자열을 다루기 위한 메서드들을 포함하는 클래스.
String 인스턴스는 한 번 생성되면 그 값을 읽기만 할 수 있고, 변경할 수 없음. → 불변 객체(immutable object)
즉, 자바에서 덧셈(+) 연산자를 이용해 문자열 결합을 수행하면, 기존 문자열의 내용이 변경되는 것이 아닌 내용이 합쳐진 새로운 String 인스턴스가 생성되는 것.
String에 할당하는 실제 이러한 “test”와 같은 값들은 Heap 메모리의 String Pool에서 관리된다.

🚀 Java String Pool

JVM이 문자열을 저장하는 특수 메모리 영역인 Java String Pool을 가진다.

자바에서 String은 불변성을 갖기 때문에, JVM이 각 literal String을 pool에 저장하는데 있어 오직 하나만 복사해서 저장함으로써 메모리를 최적화할 수 있다. 이러한 처리 과정을 interning이라고 부른다.
String 변수를 만들고 값을 할당할 때, JVM은 먼저 pool에서 해당 String과 동일한 값이 있는지 찾는다.
만약 존재한다면, 자바 컴파일러는 추가적인 메모리 할당없이 해당 주소값을 리턴할 것이다.
만약 존재하지 않는다면, pool에 값이 추가되고(intern) 이 참조값이 리턴될 것이다.

String constantString = "Bryce";
String newString = "Bryce";

Assertions.assertThat(constantString).isSameAs(newString); // 테스트 정상 통과한다.

new 연산자를 통해 String을 생성할 때 Java 컴파일러는 새로운 객체를 생성하고 JVM 용으로 예약된 힙 공간에 저장한다.
이렇게 생성된 모든 문자열은 자체 주소가 있는 다른 메모리 영역을 가리킨다.

String constantString = "Bryce";
String newString = new String("Bryce");

Assertions.assertThat(constantString).isNotSameAs(newString);

new() 연산자를 사용해 String 객체를 만들 때 항상 힙 메모리에 새 객체 생성. 이와 달리 “Bryce”와 같은 리터럴 문자열 구문을 사용하여 객체를 생성하면 String Pool에서 기존 객체가 이미 존재하는 경우 반환할 수 있음. 그렇지 않으면 String 객체를 만들고 나중에 재사용할 수 있도록 String Pool에 집어넣음.
둘의 차이점은 new 연산자는 항상 새 String 객체를 생성한다는 점이다. 또한, 리터럴을 사용해 문자열을 만들 때 intern됨.

String first = "Bryce";
String second = "Bryce";
System.out.println(first == secod); // True

String third = new String("Bryce");
String fourth = new String("Bryce");
System.out.println(third == fourth); // False

String fifth = "Bryce";
String sixth = new String("Bryce");
System.out.println(fifth == sixth); // False

일반적으로 가능하면 문자열 리터럴 표기법을 사용해야 한다. 읽기 더 쉬우며, 컴파일러가 코드를 최적화 할 수 있는 기회를 제공하기 때문.

💻수동 인턴

intern하려는 객체에서 intern() 메서드를 호출해 String Pool에 String을 수동으로 intern할 수 있음.

String constantString = "interned Bryce";
String newString = new String("interned Bryce");
assertThat(constantString).isNotSameAs(newString);


String internedString = newString.intern();
assertThat(constantString).isSameAs(internedString);

💻GC 대상인가???

Java 7 미만에서는 JVM이 Permanent Generation Space에 Java String Pool을 배치했고, 이 공간은 GC대상이 아니므로 런타임중에 확장하거나 제거할 수 없다. 때문에 Java String Pool에 많은 문자열이 들어가게 되면, OutOfMemory 에러가 발생할 수 있다. 단, Java 7 이상에서는 Heap에 들어가서 GC 대상이 된다. 이 방식의 장점은 참조되지 않는 문자열이 pool에서 제거되어 메모리 해제 되기 때문에 OutOfMemory 오류의 위험이 줄어든다는 점이다.

🚀KMP 알고리즘

불일치가 발생한 텍스트 문자열의 앞부분에 어떤 문자가 있는지 미리 알고 있기 때문에 불일치가 발생한 앞부분에 대해서 다시 비교하지 않으면서 매칭이 일어나는지 판단할 수 있는 알고리즘이다.

시간 복잡도는 O(M+N). 문자열 길이 + 패턴 길이로 선형 시간에 수행을 마칠 수 있다.

🚀StringBuffer vs StringBuilder

  • 동기화 유무
    • StringBuffer는 동기화 유
    • StringBuilder는 동기화 무
 StringStringBufferStringBuilder
StorageString PoolHeapHeap
ModifiableNo(immutable)YesYes
Thread SafeYesYesNo
SynchronizedYesYesNo
PerformanceFastSlowFast

참조