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 |