String str1 = "abc"; //문자열 리터럴 "abc"의 주소가 str1에 저장됨
String str2 = "abc"; //문자열 리터럴 "abc"의 주소가 str2에 저장됨
String str3 = new String("abc"); //새로운 String 인스턴스 생성
String str4 = new String("abc"); //새로운 String 인스턴스 생성
str1,st2가 문자열 Literal을 지정하는 방법으로 초기화 하였고, str3,str4가 String 클래스의 생성자를 사용하는 방법으로 초기화 되었다.
위 그림처럼, str1과 str2는 같은 객체를 참조하고 있지만, str3와 str4는 다른 객체를 참조하고 있다.
str1과 str2가 참조하는 객체가 String Constant Pool에 선언되어 있다.
문자열 Literal
자바 소스파일에 포함된 모든 문자열 리터럴은 컴파일 시에 클래스 파일에 저장된다.(바이트 코드)
이때 같은 내용의 문자열 리터럴은 한번만 저장된다.
문자열 리터럴도 String 인스턴스로 생성된다.
String Constant Pool이란?
Heap 영역에서 String 객체를 별도로 관리하는 장소이다.
먼저 문자열 리터럴 방식으로 String을 초기화 할 경우, String Constant Pool에 해당 문자열이 존재하는지 여부를 체크하고 있는경우 해당 리터럴의 주소를 할당하고 없는경우엔 해당 문자열을 값을 가지는 객체를 String Constant Pool에 생성한다.
위의 과정을 수행하는 메서드가 String 클래스 내의 intern()이다. 해당 메서드는 String 인스턴스의 주소값을 반환한다.
String 생성자를 사용해서 인스턴스를 만들어서 초기화 할 경우, String Constant Pool 바깥 영역에 객체를 생성한다.(Heap 영역 내이지만)
아래의 코드를 보면 intern() 의 동작 방식을 이해 할 수 있다.
public class Intern {
public static void main(String[] args) {
String literal = "brido";
String object = new String("brido");
String intern = object.intern();
System.out.println(literal == object); // false
System.out.println(literal.equals(object)); // true
System.out.println(literal == intern); // true
/*
아래 라인에서 true가 리턴되는 이유는 intern()은 "brido"를
String Constant Pool에서 검색하고, 존재하는 리터럴이기 때문에
해당 주솟값을 리턴하기 때문이다.
*/
System.out.println(literal.equals(intern)); // true
}
}