String equals에 대한 고찰

2025. 1. 26. 22:14개발/Java

String은 값을 할당하는 방법이 2가지가 있다.

String str1 = new String("hello");
String str2 = "hello";

new String으로 할당하면 이는 Heap 메모리에 올라가게 되고

Literal로 할당을 하면 String pool에 저장이 된다.

Literal로 값을 할당하면 나중에 같은 내용의 String이 있을 때 새로운 객체를 생성하지 않고 기존 객체를 참조한다.

그럼 아래와 같은 결과를 얻을 수 있다.

@Test
void test() {
    String s = "hello";
    String s2 = "hello";

    assertThat(s == s2).isTrue();
}

반면에 new로 할당을 하면 Heap 메모리에 올라가게 되므로 String pool에 같은 문자열이 있다 하더라도 Heap에 새로운 객체를 만들게 된다.

@Test
void stringTest() {
    String s1 = "hello";
    String s2 = new String("hello");

    assertThat(s1 == s2).isFalse();
    assertThat(s1.equals(s2)).isTrue();
}

그럼 String의 equals()를 살펴보자(Java21 기준)

 /**
 * Compares this string to the specified object.  The result is {@code
 * true} if and only if the argument is not {@code null} and is a {@code
 * String} object that represents the same sequence of characters as this
 * object.
 **/
public boolean equals(Object anObject) {
    if (this == anObject) {
        return true;
    }
    return (anObject instanceof String aString)
            && (!COMPACT_STRINGS || this.coder == aString.coder)
            && StringLatin1.equals(value, aString.value);
}

public static boolean equals(byte[] value, byte[] other) {
    if (value.length == other.length) {
        for (int i = 0; i < value.length; i++) {
            if (value[i] != other[i]) {
                return false;
            }
        }
        return true;
    }
    return false;
}

설명에도 써있지만 the same sequence of characters 일 때 true를 반환한다는 것을 알 수 있다.

그럼 `COMPACT_STRINGS`과 `coder` 는 무엇인가?

COMPACT_STRINGS가 나오게 된 배경은 다음과 같다.

Java 9 이전에는 String을 UTF-16(2byte)기반의 char[]로 저장했는데

// Java 8의 String class
public final class String
    implements java.io.Serializable, Comparable<String>, CharSequence {
    /** The value is used for character storage. */
    private final char value[];
}

대부분의 String은 ASCII라는 점에서 메모리의 낭비가 심했다. 그래서 Java9에서 Compact Strings라는 것이 도입이 되었고 ASCII 문자열은 1바이트 배열로 저장, Non-ASCII 문자열은 UTF-16 배열로 저장한다. COMPACT_STRINGS 은 Compact Strings 기능의 활성화 여부를 나타내는 정적 상수이다.

coder는 String 객체가 어떤 인코딩 형식으로 저장되었는지를 나타내는 필드이다.

ASCII 문자열이면 coder값은 0, Non-ASCII 문자열이면 coder값은 1 이다.

ASCII 문자열 예시 - "hello"

Non-ASCII 문자열 예시 - "안녕하세요"

만약 섞여 있다면? ex) "hello안녕하세요" → Non-ASCII(UTF-16, 2byte)

'개발 > Java' 카테고리의 다른 글

Reflection과 객체 생성  (0) 2024.12.02
equals()와 hashcode()  (0) 2024.11.30
ThreadLocal과 ThreadLocalMap  (0) 2024.11.17
Mutex와 Semaphore  (0) 2024.10.20
메모리 가시성  (0) 2024.10.20