String의 동작 원리에 대해서 알아보겠습니다.
다른 언어와 달리 자바에서의 string은 특별합니다. 2가지의 특이점을 가지고 있습니다.
- 클래스
- String Constant Pool
1. 왜 클래스로 만들었을 까?
자바에서 string을 클래스로 만든 이유는 불변성을 유지하기 위함입니다.
예를 들어 원시 타입으로 string을 만들 경우 다음과 같은 상황에서 단점이 생깁니다.
- 중요한 환경 변수가 외부에서 쉽게 변경이 가능해진다.
- 멀티 스레드 환경에서 공유자원으로 원시타입을 사용하게 된다면 예상치 못한 상황에 값이 변경될 여지가 있다.
반면에 클래스로 만들어 맴버 변수에 final 키워드를 사용하고, setter를 구현하지 않으면 클래스 내부의 변수 값을 바꿀 수 없게 됩니다. 이러한 측면에서 객체의 불변성을 보장할 수 있습니다.
2. String Constant Pool?
String Constant Pool은 힙(Heap) 메모리 영역에 존재하며, 문자열 리터럴을 통해 생성된 String 객체를 관리합니다.
문자열 리터럴을 사용하여 String 객체를 생성할 때, 자바는 먼저 String Constant Pool에서 해당 문자열의 존재 여부를 확인합니다. 이미 존재하는 문자열이라면, 새 객체를 생성하는 대신 해당 문자열의 참조를 반환합니다.
intern() 메서드는 주어진 String 객체를 강제로 String Constant Pool에 등록하도록 할 때 사용할 수 있습니다. intern() 메서드를 호출하면, String Constant Pool에서 해당 문자열을 찾고, 존재하면 그 참조를 반환하며, 그렇지 않으면 풀에 추가하고 그 참조를 반환합니다.
String a = "hello"; // 리터럴을 통해 생성
String b = "hello"; // 동일한 리터럴로 인해, a와 동일한 참조를 가짐
System.out.println(a == b); // true, 같은 참조이므로
String c = new String("hello"); // `new` 키워드를 사용하여 명시적으로 새 객체 생성
System.out.println(a == c); /
a와 b는 동일한 문자열 리터럴을 가리키기 때문에, String Constant Pool에서 동일한 참조를 공유합니다.
그러나 c는 new 키워드를 사용하여 새로운 String 객체를 생성했기 때문에 a 또는 b와 다른 참조를 가집니다.
이 경우, intern() 메서드를 사용하지 않는 이상, c는 String Constant Pool에 있는 문자열과 같은 내용을 가졌을지라도 별도의 객체 참조를 가지게 됩니다.