본문 바로가기
Programing/Java

Java에서 String과 new String()의 차이는?

by Tomining 2017. 8. 24.
아래와 같은 질문을 받았다.
String msg = “Hello”;
String msg = new String(“Hello”);

위 두 가지 코드 중 어떤 방식이 더 나은 방식일까?
같을까? 다를까?

몇 가지 케이스를 아래와 같이 테스트 해 보았다.
public class StringTest {
  @Test  public void String_Object_Test() {
    String msg1 = "Hello";
    String msg2 = "Hello";
    String msg3 = new String("Hello");
    String msg4 = new String("Hello");
    String msg5 = new String("Hello").intern();

    System.out.println(msg1 == msg2); // "Hello" == "Hello”    
    System.out.println(msg3 == msg4); // new String("Hello") == new String("Hello")    
    System.out.println(msg1 == msg3); // "Hello" == new String("Hello")    
    System.out.println(msg1 == msg5); // "Hello" == new String("Hello").intern()  }
}
true
false
false
true

왜 이런 결과가 나왔는지 하나씩 살펴보자.
먼저 Java Heap 메모리 구조와 String Pool이 어떤 것인지 안다는 가정하에 설명한다. 만약 모른다면 찾아보도록 하자.

“Hello”

Java에서 문자열은 String Pool로 관리된다. “Hello”라는 두 개의 문자열 변수를 지정했지만 JVM Heap 메모리의 String Pool에는 “Hello”라는 문자열 하나만 존재한다. 두 변수(msg1, msg2)는 reference로 가르키게 된다.



new String(“Hello”)

new 키워드는 Heap에 객체를 생성하게 된다.



new String(“Hello”).intern()

intern() 메서드를 이용하면 String pool에 등록할 수 있다.



문자열을 지정하는 방법에 따라 메모리 상에서 어떤 차이가 있는지 확인했다.
각 문자열의 HashCode 값을 살펴보자.
@Testpublic void String_Object_Hashcode() {
  String msg1 = "Hello";
  String msg2 = "Hello";
  String msg3 = new String("Hello");
  String msg4 = new String("Hello");
  String msg5 = new String("Hello").intern();

  System.out.println(System.identityHashCode(msg1));
  System.out.println(System.identityHashCode(msg2));
  System.out.println(System.identityHashCode(msg3));
  System.out.println(System.identityHashCode(msg4));
  System.out.println(System.identityHashCode(msg5));
}
1543727556
1543727556
736709391
225493257
1543727556

new 로 생성한 객체의 경우는 HashCode 값이 다르지만 String Pool을 Reference 하는 경우는 같음을 확인할 수 있다.
== 로 비교시 결과가 왜 다르게 나왔는지 확인이 된 것이다.

결론

String과 new String()은 같은 값을 갖더라도 메모리 상에서 처리되는 방식이 다르다.
그렇다면 어떤 방식을 사용하는 것이 맞을까? 보통 String Pool을 활용하는 방법을 사용할 것이다.
굳이 객체로 만들어 GC 대상이 되는 것보다 String Pool로 활용하는 것이 맞지 않을까? 만약 한 번 쓰이고 버려지는 문자열이라면 객체로 만들어 GC 대상이 되도록 할 수도 있을 것 같다.
두 가지 방법에 대한 메모리 효율 비교는 의미가 없는 것 같다. 문자열이 차지하는 메모리는 크지 않을 것이기 때문이다.
 
Tip. 문자열을 비교할 때에는 꼭 equals()를 사용하자. 간혹 코드를 보다보면 == 비교연산자를 사용하는 코드가 있긴 하다. 


참고