String

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

 

Interface

  • Serializable
    • 직렬화 및 역직렬화가 가능한지를 알려주는 마커역할을 하는 인터페이스다.
    • 직렬화는 객체를 저장하거나 전송할 때 객체의 상태를 바이트 스트림으로 변환하여 전송하는 걸 말한다.
    • 역직렬화는 이렇게 변환된 바이트 스트림을 다시 원래 객체로 변환하는 걸 말한다.
    • 객체 그대로 전송하면 복잡한 상태를 보존하기 어렵기 때문에 관리하기 쉬운 바이트 스트림으로 전송 저장한다.
  • Comparable<String>
    • 숫자는 비교할 기준이 존재한다.(크기) 하지만 사용자가 정의한 클래스라면 어떤 속성들로 비교를 할지 모호하다. 그렇기에 Comparable인터페이스의 메서드인 compareTo메서드를 구현함으로써 자신 뭘 기준으로 비교를 할지 정할 수 있다.
    • String에 경우 str.compareTo(anotherStr) 이렇게 사용하는데 str과 anotherStr을 비교하여 같으면 0, str이 사전순으로 앞에 있다면 음수값, str이 뒤에 있다면 양수값을 출력해 준다.
  • CharSequence
    • 이 인터페이스는 문자열을 다루는 클래스에서 공통으로 사용될 메서드를 포함한다. 아래의 메서드를 사용할 수 있다.
      • char charAt(jint index): 해당 인덱스의 해당하는 문자 반환
      • int length(): 문자열 길이 반환
      • CharSequence subSequence(int start, int end): 시작인덱스부터 끝인덱스까지의 부분문자열 반환
        • String에서 substring으로 부분문자열을 리턴해준다.
      • String toString(): 문자열 출력을 위해 문자열 객체 반환
  • Constable & ConstantDesc
    • 이 둘은 상수풀 관련한 것 같은데 아직 잘 모르겠다.

String의 객체는 불변이다. 

    @Stable
    private final byte[] value;
    
    //인코딩 방식을 의미 LATIN1 & UTF16 이거 중 하나가 들어감
    private final byte coder;

final로 되어있어 변경 불가이다.

 

하나 특이한 점이 있다면 문자 리터럴로 생성 시 문자열 상수풀에 저장되고 다른 객체가 동일한 문자열을 생성 시 원래 만들어 놓은 걸 가져다 쓴다. 그렇기에 1,2의 주소가 같다.

하지만 new로 새로운 객체를 만들면 동일한지 아닌지 상관없이 새로운 객체를 힙에 생성한다.

String str1 = "hello";
String str2 = "hello";

String str3 = new String("hello");
String str4 = new String("hello");

//str1 == str2
//str3 != str4

 

돌아가서 String은 불변이라 했다. 이로써 얻는 장점도 물론 존재한다.

안정성과 재사용성이 있겠다.

하지만 불변이므로 생기는 문제도 있을 수 있다.

수정을 할 수 없기에 수정하는 것처럼 보이는 것은 전부 새로운 객체를 추가적으로 만들고 그 객체를 가리키게 바꾼 것이다.

잦은 수정은 성능을 떨어트일 수 있다.

아래의 두 클래스는 문자열을 수정할 수 있는 클래스이다.

 

StringBuilder

public final class StringBuffer
    extends AbstractStringBuilder
    implements Serializable, Comparable<StringBuffer>, CharSequence

 

StringBuffer

public final class StringBuilder
    extends AbstractStringBuilder
    implements java.io.Serializable, Comparable<StringBuilder>, CharSequence

 

Abstract Class

  • AbstractStringBuilder
abstract class AbstractStringBuilder implements Appendable, CharSequence {
    /**
     * The value is used for character storage.
     */
     //실질적 데이터 !가변!
    byte[] value;

    /**
     * The id of the encoding used to encode the bytes in {@code value}.
     */
    byte coder;

    /**
     * The count is the number of characters used.
     */
    int count;

    private static final byte[] EMPTYVALUE = new byte[0];

    /**
     * This no-arg constructor is necessary for serialization of subclasses.
     */
    AbstractStringBuilder() {
        value = EMPTYVALUE;
    }

    /**
     * Creates an AbstractStringBuilder of the specified capacity.
     */
    AbstractStringBuilder(int capacity) {
        if (COMPACT_STRINGS) {
            value = new byte[capacity];
            coder = LATIN1;
           
        } else {
            value = StringUTF16.newBytesFor(capacity);
            coder = UTF16;
        }
    }
        AbstractStringBuilder(String str) {
        int length = str.length();
        int capacity = (length < Integer.MAX_VALUE - 16)
                ? length + 16 : Integer.MAX_VALUE;
        final byte initCoder = str.coder();
        coder = initCoder;
        value = (initCoder == LATIN1)
                ? new byte[capacity] : StringUTF16.newBytesFor(capacity);
        append(str);
    }

 

Interface

  • Serializable
  • Comparable<StringBuffer>
  • CharSequence

이 둘은 동시성 제어를 지원하냐 안하냐의 차이만 존재한다.

Buffer에 경우 Sychronized 키워드를 통해 동시성을 제어한다.(성능은 낮아질 수 있기에 멀티스레드 환경이 아닌 코테에서는 사용X)

 

같은 추상클래스를 확장하고 있는데 이곳에는 append, remove 등과 같은 구현해야할 메서드들을 적어놨다.

둘 다 실제 데이터인 바이트 배을은 이 추상 클래스에 두고 사용한다.

AbstractStringBuilder append(AbstractStringBuilder asb) {
    if (asb == null) {
        return appendNull();
    }
    int len = asb.length();
    ensureCapacityInternal(count + len);
    if (getCoder() != asb.getCoder()) {
        inflate();
    }
    asb.getBytes(value, count, coder);
    count += len;
    return this;
}

append의 경우 이미 구현해 놓고 아래와 같이 오버라이딩해서 사용한다.

public StringBuilder append(StringBuffer sb) {
    super.append(sb);
    return this;
}

    @Override
    public StringBuilder reverse() {
        super.reverse();
        return this;
    }

 

'공부일지 > Java' 카테고리의 다른 글

JAVA, 스트림(Stream)  (0) 2024.10.23
[JAVA] Arrays.asList()  (0) 2024.07.04
[JAVA] 6/21에 배운 것  (0) 2024.06.26
[JAVA] 6/20 배운거 클래스  (0) 2024.06.20
[JAVA] 인터페이스와 객체지향  (0) 2024.06.19

+ Recent posts