StringとStringBuilderの違い

5090 ワード

StringとStringBuilderの最も主要な違いは文字列接続操作の効率に現れている.
Stringは、リロード演算子+または+=を使用して文字列接続を行い、次のコードがあります.
public class Concatenation {
	public static void main(String[] args) {
		String str = "My";
		String introduction = str + " name " + " is " + " cgw ";
		System.out.println(introduction);
	}
}

Javapによる逆コンパイルにより、JVMによって生成されたバイトコードを得ることができます.
public Concatenation();
  Code:
   0:	aload_0
   1:	invokespecial	#1; //Method java/lang/Object."<init>":()V
   4:	return

public static void main(java.lang.String[]);
  Code:
   0:	ldc	#2; //String My
   2:	astore_1
   3:	new	#3; //class java/lang/StringBuilder
   6:	dup
   7:	invokespecial	#4; //Method java/lang/StringBuilder."<init>":()V
   10:	aload_1
   11:	invokevirtual	#5; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
   14:	ldc	#6; //String  name 
   16:	invokevirtual	#5; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
   19:	ldc	#7; //String  is 
   21:	invokevirtual	#5; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
   24:	ldc	#8; //String  cgw 
   26:	invokevirtual	#5; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
   29:	invokevirtual	#9; //Method java/lang/StringBuilder.toString:()Ljava/lang/String;
   32:	astore_2
   33:	getstatic	#10; //Field java/lang/System.out:Ljava/io/PrintStream;
   36:	aload_2
   37:	invokevirtual	#11; //Method java/io/PrintStream.println:(Ljava/lang/String;)V
   40:	return

}

mainメソッドでは、JVMはnewのStringBuilderオブジェクトであり、appendメソッドを呼び出して文字列接続操作を行うことがわかります.
 
それなら、StringBuilderオブジェクトを使用するのではなく、Stringを直接使用して、JVMに自動的に最適化させることができますか?
次のコードを参照してください.
import java.lang.StringBuilder;

public class WhitherStringBuilder {

	public String implicit(String[] fields) {
		String result = "";
		for(int i = 0 ; i < fields.length ; i++) {
			result += fields[i];
		}
		return result;
	}
	
	public String explicit(String[] fields) {
		StringBuilder result = new StringBuilder();
		for(int i = 0 ; i < fields.length ; i++) {
			result.append(fields[i]);
		}
		return result.toString();
	}

}
 
同様に逆コンパイルを行います.
public class WhitherStringBuilder extends java.lang.Object{
public WhitherStringBuilder();
  Code:
   0:	aload_0
   1:	invokespecial	#1; //Method java/lang/Object."<init>":()V
   4:	return

public java.lang.String implicit(java.lang.String[]);
  Code:
   0:	ldc	#2; //String 
   2:	astore_2
   3:	iconst_0
   4:	istore_3
   5:	iload_3
   6:	aload_1
   7:	arraylength
   8:	if_icmpge	38
   11:	new	#3; //class java/lang/StringBuilder
   14:	dup
   15:	invokespecial	#4; //Method java/lang/StringBuilder."<init>":()V
   18:	aload_2
   19:	invokevirtual	#5; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
   22:	aload_1
   23:	iload_3
   24:	aaload
   25:	invokevirtual	#5; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
   28:	invokevirtual	#6; //Method java/lang/StringBuilder.toString:()Ljava/lang/String;
   31:	astore_2
   32:	iinc	3, 1
   35:	goto	5
   38:	aload_2
   39:	areturn

public java.lang.String explicit(java.lang.String[]);
  Code:
   0:	new	#3; //class java/lang/StringBuilder
   3:	dup
   4:	invokespecial	#4; //Method java/lang/StringBuilder."<init>":()V
   7:	astore_2
   8:	iconst_0
   9:	istore_3
   10:	iload_3
   11:	aload_1
   12:	arraylength
   13:	if_icmpge	30
   16:	aload_2
   17:	aload_1
   18:	iload_3
   19:	aaload
   20:	invokevirtual	#5; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
   23:	pop
   24:	iinc	3, 1
   27:	goto	10
   30:	aload_2
   31:	invokevirtual	#6; //Method java/lang/StringBuilder.toString:()Ljava/lang/String;
   34:	areturn

}

注意:
implicitメソッドはStringの+操作を使用して文字列接続を行い、バイトコードの8-35行目を観察します.これはループです.new StringBuilderオブジェクトの操作はループ内で行われていることがわかります.これは、ループのたびに新しいStringBuilderオブジェクトが作成されることを示しています.
explicitメソッドはStringBuilderオブジェクトを使用するappendメソッドを文字列接続し、JVMは0行目にStringBuilderオブジェクトを作成し、ループは13~27行目で、StringBuilderを使用して文字列接続を行うとStringBuilderオブジェクトが1つしか作成されません.
 
以上よりStringBuilderの文字列接続の操作効率はStringよりはるかに高いことが分かった.
 
StringBuilderのスレッドセキュリティ特性は、追加のオーバーヘッドをもたらすため、StringBufferの効率はStringBufferよりもやや高い.