# String, StringBuilder, StringBuffer

# String

String은 Java의 대표적인 (Immutable Object)불변 객체이다. + 연산자를 통하여 문자열을 붙이는 경우 기존 문자열에 유연하게 추가하는 것이 아니라 새롭게 객체를 할당하여 반영한다.

String str = "hello";
String += "world";

위 코드의 메모리 구조를 간략히 표현하면 아래와 같다.

str 참조 변수는 "hello" 객체를 참조하다가 "helloworld" 객체를 참조하도록 재할당한다. 기존에 참조하던 "hello"는 GC에 의해 사라진다.

String str = "hello";
System.out.println(System.identityHashCode(str));
str += "world";
System.out.println(System.identityHashCode(str));

아래 출력 결과를 보면 서로 다른 주소 값을 가지고 있는 것을 확인할 수 있다.

968514068
785992331

identityHashCode(Object x)

String은 문자열 value를 활용하여 hashCode를 생성한다. 만약 같은 문자열을 가지고 있을 경우 같은 hashCode를 반환한다. identityHashCode를 사용하면 오버라이딩이 안된 객체 고유한 hashCode를 반환한다.

즉 문자열을 수정하는 시점에 새로운 String 인스턴스가 생긴다. String으로 생성한 문자열이 빈번하게 수정되면 힙 메모리에 많은 가비지가 생성되어 해당 애플리케이션에 치명적인 영향을 끼칠 우려가 있다.

# 가변성

이를 해결하기 위해 가변성을 가지는 StringBufferStringBuilder를 도입했다. 내부의 append(), delete() 등을 사용하면 동일 객체내에서 문자열 변경을 가능하게 한다.

StringBuffer와 StringBuilder는 동일한 인터페이스를 지원한다. 가장 큰 차이점은 synchronized 키워드를 활용한 동기화의 유무이다.

# StringBuffer

StringBuffer는 대부분의 메서드를 synchronized 키워드를 사용하여 동기화하고 있다. 덕분에 멀티 스레드 환경에서 안전하게 사용이 가능하다.

public final class StringBuffer
    extends AbstractStringBuilder
    implements java.io.Serializable, Comparable<StringBuffer>, CharSequence
{
    ...
    @Override
    @HotSpotIntrinsicCandidate
    public synchronized StringBuffer append(String str) {
        toStringCache = null;
        super.append(str);
        return this;
    }

    public synchronized StringBuffer append(StringBuffer sb) {
        toStringCache = null;
        super.append(sb);
        return this;
    }
    ...
}

# StringBuilder

동기화를 보장하지 않는 StringBuilder보다 멀티 스레드에서 안전StringBuffer가 항상 좋다고 생각할 수 있다.

하지만 sychronized를 사용하여 lock을 걸고 푸는 과정에서 생기는 오버헤드로 인하여 속도가 느리다. 단편적으로 보면 동기화를 신경 쓰지 않는 StringBuilder가 보다 빠른 속도를 가지고 있다.

# References

Java - System.identityHashCode()와 hashCode()의 차이점 (opens new window)
String 클래스를 조심히 사용하자. (opens new window)
[Java] String, StringBuffer, StringBuilder 차이 및 장단점 (opens new window)

#Java #String #StringBuilder #StringBuffer
last updated: 12/5/2021, 9:30:28 PM