public final class String //자바 21 기준
implements java.io.Serializable, Comparable<String>, CharSequence,
Constable, ConstantDesc {
@Stable
private final byte[] value; // 문자열 보관
// ... 여러 필드
// ... 여러 생성자
// ... 여러 메서드
public String concat(String str){...}
public String replace(char oldChar, char newChar){...}
...
}
String 클래스는 직접 다루기 불편한 char[ ]을 내부에 감추고 String 문자열로 다룰 수 있도록 제공한다.
String 클래스는 문자열로 처리할 수 있는 다양한 기능을 제공한다.
String 클래스 비교할 때는 항상 equals() 비교를 해야 한다.
String 을 비교할 때 new String()으로 생성됐는지 리터널로 생성됐는지 알 수 없기 때문에 equals()로 동등성 비교를 해야 한다.
String str = "hello";
위와 같이 문자열 리터널을 사용하는 경우 자바는 메모리 효율성과 성능 최적화를 위해 String Pool을 사용한다.
JVM이 클래스를 로딩하고 문자열 리터럴을 처리하는 과정에서 String Pool에 해당 문자열을 등록하거나 기존 문자열을 재사용한다. (같은 문자열이 있으면 만들지 않음) : 캐싱
"hello" 문자열 리터널을 사용하므로 문자열 풀에서 str과 같은 참조를 사용한다.
문자열 풀 덕분에 문자를 사용하는 경우 메모리 사용을 줄이고 문자를 만드는 시간도 줄어 성능도 최적화된다.
정리
문자열 리터럴은 String Pool에서 관리된다.
같은 내용의 문자열 리터럴이 이미 존재하면 새로운 객체를 만들지 않고 기존 객체의 참조를 재사용한다.
이를 통해 메모리 사용량과 문자열 객체 생성 비용을 줄일 수 있다.
String 은 불변객체이다.
변경이 필요한 경우는 기존 값을 변경하지 않고 새로운 결과를 반환해 할당해야 한다.
String 왜 불변으로 설계됐을까?
만약 String 내부의 값을 변경할 수있다면, 기존에 String Pool에서 같은 문자를 참조하는 변수의 모든 문자가 함께 변경돼 버리는 문제가 발생한다.
strA가 참조하는 문자를 변경하면 strB의 문자도 함께 변경돼 사이드 이펙트 문제가 발생한다.
문자열 정보 조회
문자열 비교
문자열 검색
문자열 조작 / 변환
문자열 분할 / 조합
기타 유틸리티
참고
CharSequence는 String, StringBuilder의 상위 타입으로,
다양한 객체를 받을 수 있다.
불변인 String 클래스의 단점은 문자를 더하거나 변경할 때마다 새로운 객체를 생성해야 한다는 점이다.
문자를 자주 변경해야 하는 상황이면 String 객체를 만들고 GC 해야한다.
결과적으로 CPU, 메모리 자원을 더 많이 사용하게 된다.
이런 문제를 해결하기 위해 자바는 StringBuilder 라는 가변 Strin을 제공한다.
public final class StringBuilder
extends AbstractStringBuilder
implements java.io.Serializable,
Comparable<StringBuilder>,
CharSequence {
}
abstract class AbstractStringBuilder
implements Appendable, CharSequence {
byte[] value;
}
StringBuilder은 AbstaractStringBuilder를 상속해 value를 사용한다.
가변이므로 final이 안 붙어있다.
StringBuilder sb = new StringBuilder();
sb.append("1");
sb.insert(1, "2");
sb.delete(0,1);
sb.reverse();
StringBuilder은 보통 문자열을 변경하는 동안만 사용하다가 문자열 변경이 끝나면 안전한 불변 String으로 변환하는 것이 좋다.
String ab = "a" + "b" ;
자바는 문자열 리터럴끼리 + 할시 문자열 결합 연산을 하지 않고 자동으로 합쳐준다.
연산이 일어나지 않기 때문에 성능이 향상된다.
String a = "a";
String b = "b";
String ab = a + b;
컴파일 시점에는 변수에 어떤 값이 들어있는지 알수 없기 때문에 단순하게 합칠 수 없다.
String ab = new StringBuidler().append(a).append(b).toString();
자바에서 StringBuilder로 변환하여 문자열을 더한 뒤 다시 불변 String으로 변환하여 최적화한다.
StringBuilder를 직접 사용하는 것이 더 좋은 경우
참고: StringBuilder vs StringBuffer
StrinBuilder 와 똑같은 기능을 수행하는 StringBuffer 클래스도 있다.
StringBuffer는 내부에 동기화가 되어 있어서, 멀티 스레드 상황에서 안전하지만 동기화 오버헤드로 인해 성능이 느리다.StringBuilder는 멀티 쓰레드 상황에서 안전하지 않지만 동기화 오버헤드가 없으므로 속도가 빠르다.
public Number plus(int plusNum) {
num += plusNum;
return this;
}
plus 메서드를 보면 자기 자신(this)의 참조값을 반환한다.
Number num1 = new Number();
num1.add(1);
num1.add(2);
num1.add(3);
num2.add(1).add(2).add(3);
아래 num2처럼 메서드 호출 결과로 자기 자신의 참조값을 반환하면, 반환돼 참조값을 사용해 메서드 호출을 계속 이어나갈 수 있다.
이런 기법을 Method Chaining 이라고 한다.