StringStringBuilder, StringBufferソースコード解析
String
private final char value[];
public String() {
this.value = "".value;
}
public String(String original) {
this.value = original.value;
this.hash = original.hash;
}
public String(char value[]) {
this.value = Arrays.copyOf(value, value.length);
}
図からわかるように、Stringは文字の配列で構成され、finalキーワードによって変更されます。
String a = "abc";
a = a + "d";
System.out.println(a);
StringBuffer buffer = new StringBuffer();
buffer.append("a");
System.out.println(buffer);
StringBuilder builder = new StringBuilder();
builder.append("b");
System.out.println(builder);
上記のコードのように、まずStringオブジェクトaを作成し、それに "abc "を代入します。その後、Java仮想マシンは別のStringオブジェクトaを作成し、元のaの値と "d "を足してから新しいaに代入します。元のaはJava仮想マシンのゴミ収集メカニズムによってリサイクルされます。元のaはJava仮想マシンのガベージ・コレクション・メカニズムによってリサイクルされるので、aは実際には変更されていません。このように、頻繁に操作する文字列にString型を使用することはお勧めできません。新しいオブジェクトを作成し、古いオブジェクトをリサイクルするという処理になるため、実行速度が非常に遅くなります。
String + 動作原理
public static void main(String[] args) {
int num = 10;
String a = "abc";
long time = System.currentTimeMillis();
String b = "hello world";
for (int i = 0; i < num; i++) {
a = a + b;
System.out.println(a);
}
}
JDK9 以前のバージョンでは、String の + 操作は StringBuilder オブジェクトを作成し、そのオブジェクトの append() メソッドを呼び出すことで実装されていました。
JDK11、デコンパイル済み。
// JDK9からは、文字列連結操作はinvokedynamicディレクティブを使ってコンパイルされる。invokedynamicディレクティブは、ブートストラップ・メソッドjava.lang.invoke.StringConcatFactory.makeConcatWithConstants
// jDK11を使用し、デコンパイルしたコード
public static void main(final String[] args) {
final int num = 10;
String a = "abc";
final long time = System.currentTimeMillis();
for (int i = 0; i < num; ++i) {
a = invokedynamic(makeConcatWithConstants:(Ljava/lang/String;)Ljava/lang/String;, a); //
System.out.println(a);
}
}
StringBuffer
public class StringBuffer extends AbstractStringBuilder{
// char文字を配列に格納する
char[] value;
public StringBuffer() {
// デフォルトの初期化は16である。
super(16);
}
}
StringBufferもソースコードからわかるように、一番下はchar配列で、デフォルトの初期容量は16です。 StringBufferの拡張は、下図からわかるように、古い配列に2を足して拡張します。
ここでは、StringBufferの演算子関数appendを見てみましょう。 appendメソッドはsynchronizedによって変更され、スレッドセーフです。
StringBuilder
AbstractStringBuilder
StringBuilderとStringBufferは、どちらもStringBuilderを継承しているため、初期スペースや展開の仕方は同じです。
public final class StringBuilder
extends AbstractStringBuilder {
// char文字を配列に格納する
char[] value;
public StringBuilder() {
// デフォルトの初期化は16である。
super(16);
}
}
StringBuilderとStringBufferの違いは、下のイメージにあるように、append()メソッドにsynchronized修飾子がないため、StringBuilderはスレッドセーフではありません。
概要
StringBuffer と StringBuilder の長さは可変です StringBuffer はスレッドセーフです StringBuilder はスレッドセーフではありません したがって: String: 文字列操作の数が少ない場合 StringBuilder: 操作の数が多い文字バッファに対するシングルスレッド操作の場合 StringBuffer: 操作の数が多い文字バッファに対するマルチスレッド操作の場合StringBuffer: 文字バッファに対して多数の操作が実行されるマルチスレッド状況用。