자바 (ref. 자바의정석)

String 클래스 - JAVA

쿠쿠s 2022. 2. 24. 16:55

 

String 클래스


실제로 코테에서도 많이 활용되고, 자바의 정석에서도 중요하다고 강조를 하셔서 정리를 하게 되었습니다.

 

 

String 클래스변경 불가능한(immutable) '클래스' 입니다. 클래스이기 때문에 String 은 기본 타입(Primitve Type)이 아닌 참조 타입(Reference Type)입니다.

 

 

아래 코드를 보면 String 클래스에는 문자열을 저장하기 위해서 byte[] 배열 변수 value 를 인스턴스 변수로 정의하고 있습니다.

public final class String
    implements java.io.Serializable, Comparable<String>, CharSequence,
               Constable, ConstantDesc {

    /**
     * The value is used for character storage.
     *
     * @implNote This field is trusted by the VM, and is a subject to
     * constant folding if String instance is constant. Overwriting this
     * field after construction will cause problems.
     *
     * Additionally, it is marked with {@link Stable} to trust the contents
     * of the array. No other facility in JDK provides this functionality (yet).
     * {@link Stable} is safe here, because value is never null.
     */
    @Stable
    private final byte[] value;

    ...
    이하생략
    ...
}

 

한번 생성된 String인스턴스가 갖고 있는가 갖고 있는 문자열은 읽어 올 수만 있고 변경할 수는 없습니다. 흔히 스트링 변수를 선언하고 변수에 '+' 써서 사용을 많이 하셨을 겁니다. '+' 연산을 사용 했을 때 인스턴스의 문자열 자체가 바뀌는 것이 아닌 새로운 문자열을 가진 String 인스턴스가 생성하여 메모리공간을 차지하게 됩니다.

 

그래서 문자열이 자주 변경할일이 있을 경우에 가변(mutable)특성을 가진 StringBuilder 또는 StringBuffer 클래스를 사용하는 것이 좋습니다. 해당 클래스는 저장된 문자열의 변경이 가능합니다.

 

*StringBuffer 클래스

  • 내부적으로 문자열 편집을 위한 버퍼(buffer)를 가지고 있고, 인스턴스를 생성할때 크기 지정이 가능합니다.
  • 문자열 길이를 고려하여 크기를 지정하지 않으면 지정 크기를 넘어갈 때 버퍼를 늘리는 작업을 합니다.
  • append( ) 의 반환타입은 자신의 주소를 반환, 그래서 같은 인스턴스를 가지며 연속 호출이 가능
  • 멀티 스레드에 안전(thread safe) 하도록 동기화 되어있다. 하지만 동기화는 성능을 떨어뜨린다. -> 스레드 사용하는게 아니라면 StringBuilder 사용

 

class StringEx {
    public static void main(String[] args) throws CloneNotSupportedException {


        String s1 = "abc";
        s1 += "d";
        System.out.println(s1);


        String s2 = "abcd";
        System.out.println(s1 == s2);
        System.out.println(s1.equals(s2));
    }
}

출력 결과

각 String인스턴스의 주소를 등가비교연산자 '==' 로 비교했을 때 결과는 false입니다. 실제 두 문자열의 내용을 비교하는 equals를 사용하면 같다고 출력이 됩니다. 

 

 

 

 

 

그러면 JAVA 의 String 은 왜 불변으로 설계되었을까요?

 

1. 자바는 스트링을 String constant pool에서 관리를 하여 Heap 영역의 많은 메모리를 절약할 수 있습니다. 같은 값은 String에 대해 같은 메모리를 참조하게 할 수 있기 때문입니다. 

 

2. 불변 객체이기 때문에 값이 바뀔 일이 없기 때문에 멀티 쓰레드 환경에서 안전(thread-safe)합니다. 동기화에 대해 신경 쓰지 않아도 되기 때문에 내부 데이터를 자유롭게 공유 가능합니다.

 

3. 문자열은 자바 애플리케이션에서 사용자의 이름, 암호, URL, 등등 중요한 정보를 저장하는 데 사용됩니다. 불변이기에 값이 변경되는 것을 예방하여 보안상의 이점을 가집니다.

 

4. String의 hashCode( ) 는 최초 1번만 실제 계산 로직을 수행하고 이후 해당 값을 리턴만 하도록 오버라이딩 되어 있습니다. hascode를 key로 사용하는 HashMap 경우에 효과를 발휘합니다. 다른 객체는 키로 쓰일 때마다 hashcode를 계산해야 하는데 String은 캐싱을 하고 있기 때문에 더 빠른 속도로 사용할 수 있습니다.

 

 

 

 

 

*String 클래스의 생성자와 메서드

String 클래스 내에 정의된 생성자 메서드 목록을 실제 강의 또는 코딩테스트에서 자주 보였던 내용들만 정리해 봤습니다. 

 

  1. String(String s): 주어진 문자열(s)를 갖는 String 인스턴스를 생성한다.
  2. String(Char[] value): 주어진 문자열(value)를 갖는 String 인스턴스를 생성한다.
  3. int compareTo(String str): 문자열(str)과 사전순서로 비교한다. 같으면 0, 사전 순으로 이전이면 음수, 이후면 양수를 반환한다.
  4. boolean contains(charSequence s): 지정된 문자열(s)이 포함되었는지 검사
  5. boolean equlasIgnoreCase(String str): 문자열과 String인스턴스의 문자열을 대소문자 구분없이 비교한다.
  6. int indexOf(int ch): 주어진 문자(ch)가 문자열에 존재하는지 확인하여 위치(index)를 알려준다. 못 찾으면 -1 반환 (index는 0부터 시작)
  7. int length(): 문자열의 길이를 알려준다.
  8. ★String replace(char old, char nw): 문자열 중의 문자(old)를 새로운 문자(nw)로 바꾼 문자열을 반환한다.
  9. ★String replace(CharSequence old, CharSequence nw): 문자열중 문자열(old)을 새로운 문자열(nw)로 바꾼 문자열 반환
  10. ★String replaceAll(String regex, String replacement): 문자열 중에서 지정된 문자열(regex)과 일치하는 것을 새로운 문자열(replacement)로 모두 변경한다.
  11. ★String subString(int begin), String subString(int begin, int end): 주어진 시작위치(begin)부터 끝 위치(end) 범위에 포함된 문자열을 얻는다. 이 때!! 시작 위치의 문자는 범위에 포함되지만, 끝 위치의 문자는 포함되지 않는다. (begin <= x < end)
  12. String toLowerCase(): String 인스턴스에 저장되어있는 모든 문자열을 소문자로 변환
  13. String toString(): String 인스턴스에 저장되어 있는 문자열을 반환