public final class String implements java.io.Serializable, Comparable<String>, CharSequence {
@Stable
private final byte[] value;
private final byte coder;
private int hash;
// ...
}
String() {}
String(byte[] bytes) {}
String(byte[] bytes, Charset charset) {}
String(byte[] bytes, int offset, int length) {}
String(byte[] bytes, int offset, int length, Charset charset) {}
String(byte[] bytes, int offset, int length, String charsetName) {}
String(byte[] bytes, String charsetName) {}
String(char[] value) {}
String(char[] value, int offset, int count) {}
String(int[] codePoints, int offset, int count) {}
String(String original) {}
String(StringBuffer buffer) {}
String(StringBuilder builder) {}
String s1 = new String("luca");
String s2 = new String("luca");
힙역영
모든 쓰레드가 공유하며, new 키워드로 생성된 객체와 배열이 생성되는 영역입니다. 또한, 메소드 영역에 로드된 클래스만 생성이 가능하고 Garbage Collector가 참조되지 않는 메모리를 확인하고 제거하는 영역입니다
값
울 표현한 것String s3 = "hello";
String s4 = "hello";
String Constant Pool
에 올라간다.ConcurrentHashMap
로 구현String s1 = new String("luca");
String s2 = new String("luca");
String s3 = "luca";
String s4 = "luca";
System.out.println(s1 == s2); //false
System.out.println(s2 == s3); //false
System.out.println(s3 == s4); //true
System.out.println(s4 == s1); // false
String s1 = new String("luca");
String s3 = "luca";
s1 = s1.intern();
System.out.println(s1 == s3); //true
String s1 = new String("luca");
s1 = s1 + "luca";
매번 + 연산을 진행할 때마다 새로운 객체를 생성하기 때문에 비효율적이다.
String은 기본적으로 불변이기 때문에 concat()
, toUpperCase()
, trim()
같은 메서드를 사용할 때도 내부의 필드가 바뀌는 것이 아니라 새로운 String 객체를 생성해서 반환한다.
public final class StringBuilder extends AbstractStringBuilder
implements java.io.Serializable, Comparable<StringBuilder>, CharSequence {
public StringBuilder() {
super(16);
}
public StringBuilder(String str) {
super(str.length() + 16);
append(str);
}
public StringBuilder append(String str) {
super.append(str);
return this;
}
}
abstract class AbstractStringBuilder implements Appendable, CharSequence {
byte[] value;
byte coder;
int count;
private static final byte[] EMPTYVALUE = new byte[0];
AbstractStringBuilder() {
value = EMPTYVALUE;
}
AbstractStringBuilder(int capacity) {
if (COMPACT_STRINGS) {
value = new byte[capacity];
coder = LATIN1;
} else {
value = StringUTF16.newBytesFor(capacity);
coder = UTF16;
}
}
public AbstractStringBuilder append(String str) {
if (str == null) {
return appendNull();
}
int len = str.length();
ensureCapacityInternal(count + len);
putStringAt(count, str);
count += len;
return this;
}
}
StringBuilder sb = new StringBuilder("luca");
sb.append("luca");
진짜로 + 연산자가 느릴까?
String s = "hello";
for(int i = 0; i < 3; i++) {
s += "luca";
}
public final class StringConcatFactory {
private enum Strategy {
/**
* Bytecode generator, calling into {@link java.lang.StringBuilder}.
*/
BC_SB,
/**
* Bytecode generator, calling into {@link java.lang.StringBuilder};
* but trying to estimate the required storage.
*/
BC_SB_SIZED,
/**
* Bytecode generator, calling into {@link java.lang.StringBuilder};
* but computing the required storage exactly.
*/
BC_SB_SIZED_EXACT,
/**
* MethodHandle-based generator, that in the end calls into {@link java.lang.StringBuilder}.
* This strategy also tries to estimate the required storage.
*/
MH_SB_SIZED,
/**
* MethodHandle-based generator, that in the end calls into {@link java.lang.StringBuilder}.
* This strategy also estimate the required storage exactly.
*/
MH_SB_SIZED_EXACT,
/**
* MethodHandle-based generator, that constructs its own byte[] array from
* the arguments. It computes the required storage exactly.
*/
MH_INLINE_SIZED_EXACT
}
public static CallSite makeConcatWithConstants(MethodHandles.Lookup lookup,
String name,
MethodType concatType,
String recipe,
Object... constants) throws StringConcatException {
if (DEBUG) {
System.out.println("StringConcatFactory " + STRATEGY + " is here for " + concatType + ", {" + recipe + "}, " + Arrays.toString(constants));
}
return doStringConcat(lookup, name, concatType, false, recipe, constants);
}
}
기본전략은 MH_INLINE_SIZE_EXACT
이 사용되기 되는데,
이 전략은 문자열 연결 작업이 특정 크기 이하일 경우,
문자열 연결 작업의 크기를 예측할 경우에 적합하다.
나머지 전략에서 대부분 StingBuilder를 사용한다.
+ 연산자
를 사용하면 버전에 따라서 최적화
가 진행된다.StringBuilder
객체를 생성하는 방식으로 진행되어 성능의 저하가 심하다.StringConcatFactory
를 사용하여 개선되었다.StringBuilder sb = newStringBuilder("hello");
for(int i = 0; i < 3; i++) {
sb.append("luca");
}
String s = sb.toString();