Java - 문자열을 다루는 방법

String 클래스

String 클래스는 문자열을 저장하기 위해 char형 배열 참조변수(char[] value)를 인스턴스 변수로 사용한다. 한 번 생성한 String 인스턴스의 문자열은 읽을 수만 있고 값을 변경할 수는 없다. String 클래스는 변경 불가능(immutable)하다. 덧셈 연산자 +는 새로운 String 인스턴스를 반환한다.

문자열간의 결합이나 추츨 등 문자열을 조작하는 작업이 많이 필요하다면 String 클래스 대신 StringBuffer 클래스를 사용하는 것이 좋다. StringBuffer 인스턴스에 저장된 문자열은 변경 가능하다.

문자열 리터럴

.java 파일에 포함된 모든 문자열 리터럴은 컴파일 시에 클래스 파일에 저장된다. 정확히 말하면 클래스 파일의 constant pool에 저장된다. 독립적으로 컴파일된 클래스 파일은 런타임에 JVM에 의해 메모리에 load되는데 이 때 각 클래스 파일들이 하나로 합쳐지게 된다. 결론은 서로 다른 클래스 파일에 존재하는 리터럴 "Hello world"을 런타임에 비교한다면 결과는 `true`이다. 문자열 리터럴은 실행 프로그램 환경에서 unique하다.

Foo.java

package main;

public class Foo {

    public String strLiteral = "Foo"; // main/Foo.java 파일의 문자열 리터럴

    public String getStrLiteral() {
        return strLiteral;
    }
}

Study.java

package main;

public class Study {

    public static void main(String[] args) {
        Foo foo = new Foo();
        String literal = "Foo"; // main/Study.java 파일의 문자열 리터럴
        System.out.println(literal == foo.getStrLiteral());
    }
}
$ javac main/Study.java main/Foo.java
$ java main.Study

결과는 true가 출력된다. 서로 다른 파일의 리터럴이라도 내용이 같다면 런타임에 동일한 객체를 참조하게 된다.

일반적으로 변수를 선언할 때 각 타입의 기본값으로 초기화 하지만 String은 참조형 타입의 기본값인 null보다는 빈 문자열로, char 타입은 기본값인 ‘\u0000’ 대신 공백으로 초기화 하는 것이 보통이다.

StringBuffer vs StringBuilder

String 클래스와 다르게 문자열을 수정할 수 있고 배열의 크기도 바꿀 수 있다. String 클래스는 equals()메서드가 내용(value)를 비교하도록 오버라이딩 되어있지만 StringBuilder는 오버라이딩 되어있지 않아 equals()메서드를 사용하면 == 연산자를 사용한 것과 같은 결과를 얻는다. (equals() 메서드의 기본동작은 ==를 사용하여 참조값을 비교하는 것이다.) 오버라이딩 없이 내용을 비교하고싶다면 toString() 메서드를 호출하여 얻은 String 인스턴스의 equals()메서드를 사용하면 된다.

StringBuffer에는 동기화가 내재되어 있고 StringBuilder는 StringBuffer에서 동기화 매커니즘만 제거한 것이다. 멀티쓰레드 환경이 아닌 경우 StringBuffer를 사용하면 성능을 떨어뜨릴 수 있기 때문이다. 하지만 StringBuffer도 충분히 성능이 좋기 때문에 굳이 StringBuffer에서 StringBuilder로 바꿀 필요는 없다.

reference

Categories:

Updated:

Comments