String constant pool

먼저 코드를 보자

1
2
3
4
5
6
7
8
String str1 = "hello";
String str2 = "hello";
String newString = new String("hello");
String intern = newString.intern();

System.out.println(str1 == str2); // true
System.out.println(str1 == newString); // false
System.out.println(str1 == intern); // true

String은 리터럴 방식으로 변수에 선언을 할 경우 String constant pool에서 해당 String을 가져오게 된다.

그러므로 str1str2는 서로 같은 참조를 가리키기 때문에 line 6에서 true가 나온 것이다.

new로 String을 변수에 선언할 경우 pool에서 String을 가져오는 것이 아니라 아닌 새로 객체를 생성하는 것이기 때문에 newString은 String constant pool에 있는 String 객체와는 다른 객체를 가리킨다.

그러므로 line 7에서 str1newString은 서로 다른 객체기 때문에 false이다.

String.intern()은 해당 String을 pool에서 찾아 해당 객체를 리턴하는 것이므로 line 8의 str1intern은 서로 같은 참조를 가리키기 때문에 true이다.

간단하게 아래와 같이 표현 가능하다.

여기서 또 하나 참고해야 할 점은 String pool은 heap에 있다는 점이다.

이는 String pool이 GC 대상이 될 수 있다는 것이다.


추가로 아래 코드를 살펴보자

1
2
3
4
5
6
7
8
String hello = "hello";
String world = "world";

String helloworld = "helloworld";

System.out.println((hello + world) == helloworld); // false
System.out.println(hello.concat(world) == helloworld); // false
System.out.println(hello.concat(world) == helloworld); // true

String은 서로 + 연산을 하게 될 경우 새로 String 객체를 생성하기 때문에 StringBuilder를 사용하라고 자주 들었을 것이다. (물론 컴파일 시에 알아서 StringBuilder로 변환해주지만)

위 코드를 통해 +나 concat을 할경우에 String constant pool에서 String을 가져오는 것이 아니라 새로운 String 객체를 생성한다는 것을 확인 할 수 있다.

참고

Share