JAva文字列接合の研究と最適化
3741 ワード
Stringはjavaでは可変であり、各Stringを操作する方法は実際には新しいStringオブジェクトを返し、元のStringオブジェクトを達成できないようにします.Stringの接続には、「+」記号を使用する方法と、StringBuilderを使用する方法、Stringのconcatを使用する方法があります.
(1) ‘+’:
'+'の実装を検討するために、次のテストコードを書きます.
code 2から,‘+’の左右に変数がある場合,StringBuilderオブジェクトが生成され,そのappendメソッドが呼び出されることが分かる.
1つの継ぎ目Stringの文で、継ぎ目StringにStringオブジェクトがある場合、この文はStringBuilderオブジェクトを生成し、appendメソッドを呼び出す.
ソースコードのループに注意してください.逆コンパイル後、コードには8 から35 が対応し、StringBuilderオブジェクトがループに含まれているため、上記のコードはStringBuilderオブジェクトを作成しすぎて効率に影響します.
(2) StringBuilder
次に、StringBuilderのappendメソッドを分析します.ソースコードは次のとおりです.
(3)Stringのconcatメソッド
ソースコードは次のとおりです.
結論:
3つの変数を定義します:String a=“a”、b=“b”、c=“c”;
1.String d=a+bのような単純な結合については、String d=a.concat(b)を使用することを推奨します.不要なStringBuilderオブジェクトの生成を低減します.
2.二次以上の接合について、例えばString d=a+b+cのように、この方式を使用すればよい
3.ループに関連する継ぎ目について、次のようにします.
(1) ‘+’:
'+'の実装を検討するために、次のテストコードを書きます.
public static void main(String[] args) {
String a="hell"+"o"; //code1
String b="world";
for(int i=0;i<4;i++) {
a+=b; //code2
}
}
上のコードをコンパイルしてjdkの逆コンパイルツール(javap)で逆コンパイルして、次のコードを得ます.public static void main(java.lang.String[]);
Code:
0: ldc #16; //String hello
2: astore_1
3: ldc #18; //String world
5: astore_2
6: iconst_0
7: istore_3
8: goto 33
11: new #20; //class java/lang/StringBuilder
14: dup
15: aload_1
16: invokestatic #22; //Method java/lang/String.valueOf:(Ljava/lang/Object;)Ljava/lang/String;
19: invokespecial #28; //Method java/lang/StringBuilder."<init>":(Ljava/lang/String;)V
22: aload_2
23: invokevirtual #31; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
26: invokevirtual #35; //Method java/lang/StringBuilder.toString:()Ljava/lang/String;
29: astore_1
30: iinc 3, 1
33: iload_3
34: iconst_4
35: if_icmplt 11
38: return
code 1から「もし‘+’程度に変数がない場合,‘+’の結果は直接得られる.code 2から,‘+’の左右に変数がある場合,StringBuilderオブジェクトが生成され,そのappendメソッドが呼び出されることが分かる.
1つの継ぎ目Stringの文で、継ぎ目StringにStringオブジェクトがある場合、この文はStringBuilderオブジェクトを生成し、appendメソッドを呼び出す.
ソースコードのループに注意してください.逆コンパイル後、コードには
(2) StringBuilder
次に、StringBuilderのappendメソッドを分析します.ソースコードは次のとおりです.
public StringBuilder append(String str) {
super.append(str);
return this;
}
super.append(str)は以下の通りである. public AbstractStringBuilder append(String str) {
if (str == null) str = "null";
int len = str.length();
if (len == 0) return this;
int newCount = count + len;
if (newCount > value.length)
expandCapacity(newCount);// StringBuilder 2
str.getChars(0, len, value, count);
count = newCount;
return this;
}
ソースコードを解析することで、StringBuilderの効率が高いことがわかります(これもjavaコンパイラがデフォルトでStringBuilderを採用している理由です).しかし、容量を拡張する操作に注意するため、初期容量を適切に設定する必要があります.(3)Stringのconcatメソッド
ソースコードは次のとおりです.
public String concat(String str) {
int otherLen = str.length();
if (otherLen == 0) {
return this;
}
char buf[] = new char[count + otherLen];
getChars(0, count, buf, 0);
str.getChars(0, otherLen, buf, count);
return new String(0, count + otherLen, buf);
}
この方法の役割は簡単で、新しいStringオブジェクトを作成することです.結論:
3つの変数を定義します:String a=“a”、b=“b”、c=“c”;
1.String d=a+bのような単純な結合については、String d=a.concat(b)を使用することを推奨します.不要なStringBuilderオブジェクトの生成を低減します.
2.二次以上の接合について、例えばString d=a+b+cのように、この方式を使用すればよい
3.ループに関連する継ぎ目について、次のようにします.
String d="";
String e="";
for(int i=0;i<10;i++) {
d+=a;// d=d+a;
e+=(a+b);// e=e+a+b;
}
以下の方法を推奨します.StringBuilder d = new StringBuilder(10)//
StringBuilder e = new StringBuilder(20);
for(int i=0;i<10;i++) {
d.append(a);
e.append(a).append(b);
}
#ここでは、「thinking in java」第4版Strings章を参照します.