자바에서 문자열을 생성할 때 크게 두 가지 방법이 있다.
- new 키워드를 사용해서 생성 (new String() 이용)
String str1 = new String("hello");
- String 리터럴을 이용해서 생성
String str1 = "hello";
두 방법의 차이는 메모리 관리 방식에 따라 달라진다.
일반적으로 자바에서 객체를 생성하면 Heap 영역에 할당된다.
new String()을 사용하면 Heap 영역에 새로운 문자열 객체를 생성하게 된다.
생성할 때마다 Heap 영역에 생성되기 때문에, 같은 값이라도 다른 객체일 수 있다.
String str1 = new String("hello");
String str2 = new String("hello");
System.out.println(str1 == str2); // false (서로 다른 객체 참조)
System.out.println(str1.equals(str2)); // true (값은 동일)
그래서 위와 같이 객체의 참조값을 확인할 수 있는 == 연산자로 확인해보면, 서로 다른 객체를 참조하고 있다.
또한 객체의 내용을 비교하는 equals 메서드로 확인하면 같은 값인 것을 알 수 있다.
""로 감싸서 문자열을 만들면, String Pool에 있는 문자열을 참조한다.
만약 컴파일 타임에 String 리터럴이 없다면, String Pool에 String 인스턴스를 미리 만들고,
String Pool에 동일한 값의 문자열이 있으면 새로 만들지 않고 참조값을 재활용 한다.
String str1 = "hello";
String str2 = "hello";
System.out.println(str1 == str2); // true (같은 객체 참조)
위의 코드에서 참조값을 확인해보면 같은 객체를 참조하고 있다는 것을 알 수 있다.
위와 같은 방법은 String이 불변 객체인 점을 이용한 것이다.
Java에서 String은 일반 객체와는 달리, 불변 객체라고 불린다.
불변 객체는 생성된 후 내부 상태를 변경할 수 없는 객체이다.
만약 String이 불변 객체가 아니었다면 외부에서 참조를 통해 내용을 수정할 수 있으므로, String Pool을 참조하는 방식을 사용하기 어려웠을 것이다.
이러한 String의 불변성 덕분에, String Pool을 활용해 문자열을 재활용 할 수 있다.
정리하면, String 리터럴 방식을 사용해서 아래의 장점을 얻을 수 있다.
원래 String Pool은 Method Area의 Permenent Generation 영역에 존재해서 고정된 크기로 제한되었지만,
Java 7 이후 런타임에 String Pool의 크기를 자동으로 조절할 수 있도록 하기 위해서 Heap 영역에서 관리된다.
