Java String 객체와 String 리터럴

이진호·2022년 8월 30일
0

JAVA

목록 보기
3/10
post-thumbnail

String 문자열의 두가지 생성 방식 new와 리터럴

Java에서 일반적으로 객체를 생성할 때 new 키워드를 사용합니다. 그러나 문자열은 특이하게도 new 키워드 뿐만 아니라 바로 값을 할당할 수도 있는데 이를 문자열 리터럴이라고 부릅니다.

public void string() {
    String name = "lxxjn0"; // 문자열 리터럴 생성
    String name1 = new String("lxxjn0"); // new 연산자를 이용한 문자열 생성
}

String Constant Pool

new 키워드 방식과 문자열 리터럴 방식은 문법적 차이 뿐만 아니라 실제 메모리에 할당되는 영역에도 차이가 있습니다.

  • new 연산자를 이용하여 문자열 객체를 생성하면 일반 객체들처럼 메모리의 Heap 영역에 할당됩니다.
  • 문자열 리터럴을 이용하여 생성하면 String Constant Pool이라는 영역에 할당됩니다.
    String Constant Pool

Java 버전과 String Constant Pool의 위치

  • Java 7 이전 버전에서는 String Constant Pool이 Perm 영역에 존재했었습니다. Perm 영역은 주로 메타 데이터를 저장하는 영역으로 GC 대상에서 제외되는 영역입니다.
  • 그러나 Java 7부터 String Constant Pool은 Heap 영역으로 옮겨졌습니다.
  • Heap 영역은 GC 대상으로 String Constant Pool에서 참조를 잃은 문자열 객체들은 다시 메모리로 반환처리 됩니다.
  • 여담으로 Perm 영역은 Java 8에서부터 삭제되었습니다.

new와 리터럴 방식의 차이

public void string() {
    String name = "lxxjn0";
    String name1 = "lxxjn0";
    String name2 = new String("lxxjn0");
    String name3 = new String("lxxjn0");
}
  • 문자열 리터럴을 사용하여 동일한 문자열을 생성할 경우 해당 객체들은 String Constant Pool 내의 동일한 객체를 바라보게 됩니다.
  • 하지만 new 연산자를 사용하여 동일한 문자열을 생성할 경우에는 Heap에서 서볼 다른 객체를 만들고 바라보게 됩니다.

new와 리터럴 방식의 차이

문자열 리터럴 생성 방식

문자열 리터럴의 경우 내부적으로 String의 intern() 메서드를 호출합니다.
intern()메서드는 String Constant Pool에 생성하려는 문자열이 이미 존재할 경우 주솟값을 반환하고 없다면 새로 객체를 생성한 후 주솟값을 반환합니다.

/**
 * Returns a canonical representation for the string object.
 * <p>
 * A pool of strings, initially empty, is maintained privately by the
 * class {@code String}.
 * <p>
 * When the intern method is invoked, if the pool already contains a
 * string equal to this {@code String} object as determined by
 * the {@link #equals(Object)} method, then the string from the pool is
 * returned. Otherwise, this {@code String} object is added to the
 * pool and a reference to this {@code String} object is returned.
 * <p>
 * It follows that for any two strings {@code s} and {@code t},
 * {@code s.intern() == t.intern()} is {@code true}
 * if and only if {@code s.equals(t)} is {@code true}.
 * <p>
 * All literal strings and string-valued constant expressions are
 * interned. String literals are defined in section {@jls 3.10.5} of the
 * <cite>The Java Language Specification</cite>.
 *
 * @return  a string that has the same contents as this string, but is
 *          guaranteed to be from a pool of unique strings.
 */
public native String intern();

자바 native 키워드

문자열은 Immutable

자바 소스 파일(.java)이 클래스 파일(.class)로 컴파일되고 JVM(Java Virtual Machine)에 올라갈 때, JVM은 String Constant Pool에 동일한 문자열이 있는지 확인하고 이미 존재한다면 재사용을 하고 없는 경우 새로운 문자열을 만듭니다.

문자열 리터럴은 이와같이 String Constant Pool에서 상수처럼 취급되기 때문에 불변(immutable) 하며 thread-safe 합니다.

추가적으로 String으로 연산을 하는 경우 문자열 변경되면 기존의 불변 객체를 수정하는 것이 아닌 새로운 객체를 만들게 됩니다.
기존 문자열은 참조가 사라지게 되고 가비지 컬렉터(Garbage Collector)의 수집 대상이 되는데 이와 같은 일련의 과정은 의도치 않은 Java 성능 이슈를 유발할 수 있습니다.

String 클래스를 조심히 사용하자

출처

0개의 댓글