最初に3つの特性を覚えておく必要があります。
1。定義
APIを見ると、その文字列、StringBuffer、およびStringBuilderがすべてCharSequenceインターフェイスを実装することがわかります。それらはすべて文字列に関連していますが、処理メカニズムは異なります。
2。シナリオを使用します
文字列クラスを使用したシナリオ:文字列が頻繁に変更されないシナリオでは、定数の宣言や少数の可変操作など、文字列クラスを使用できます。
StringBufferクラスを使用したシナリオ:文字列操作が頻繁に実行され(スプライシング、置換、削除など)、マルチスレッド環境で実行される場合、XMLの解析、HTTPパラメーターの解析、カプセル化などのStringBufferの使用を検討できます。
StringBuilderクラスを使用したシナリオ:文字列操作が頻繁に実行される場合(スプライシング、置換、削除など)、シングルスレッド環境で実行される場合、SQLステートメントアセンブリ、JSONカプセル化などのStringBuilderを使用することを検討できます。
iii。分析
簡単に言えば、文字列型と弦楽型タイプの主なパフォーマンスの違いは、実際には文字列が不変のオブジェクトであるため、文字列タイプを変更するたびに、新しい文字列オブジェクトを生成してから新しい文字列オブジェクトをポインターすることと同等です。したがって、各オブジェクトの生成がシステムパフォーマンスに影響を与えるため、特にメモリ内の参照オブジェクトが多すぎる場合、JVMのGCが機能し始めます。
StringBufferクラスを使用すると、結果は異なります。結果は、新しいオブジェクトを生成してからオブジェクト参照を変更する代わりに、stringbufferオブジェクト自体で動作するたびに動作します。したがって、一般に、特に文字列オブジェクトがしばしば変更される場合は、StringBufferを使用することをお勧めします。いくつかの特別な場合、文字列オブジェクトの文字列スプライシングは、実際にはJVMによってStringBufferオブジェクトのスプライシングとして解釈されます。したがって、文字列オブジェクトの速度は、これらの時代にStringBufferオブジェクトよりも遅くはありません。特に、次の文字列オブジェクトの生成では、文字列効率はstringbufferよりもはるかに高速です。
string s1 = "これは" + "simple" + "test"; stringbuffer sb = new StringBuilder( "this is a")。append( "simple")。append( "test");
String S1オブジェクトを生成する速度が速すぎることに驚くでしょう。現時点では、StringBufferは速度に利点がありません。実際、これはJVMのトリックです。 JVMの目には、これ
文字列s1 = "これは" + "simple" + "テスト"のみです。
実は:
文字列s1 = "これは単純なテストのみです";
したがって、もちろん時間はかかりません。しかし、ここで注意すべきは、あなたの文字列が別の文字列オブジェクトから来た場合、速度はそれほど高速ではないということです。
文字列s2 = "これはa"; string s3 = "simple"; string s4 = "test"; string s1 = s2 + s3 + s4;
この時点で、JVMは元の方法で定期的にそれを行います。
4。JVMの詳細な最適化と処理
本当に上記のパフォーマンスコストはありますか?文字列スプライシングは非常に一般的ですが、特別な処理の最適化はありませんか?答えは、この最適化がJVMで.javaにBytecodeにコンパイルするときに実行されるということです。
Javaプログラムが実行されたい場合、時間と実行時間をコンパイルし、2つの期間がかかります。コンパイル時に、Java JVM(コンパイラ)はJavaファイルをByteCodeに変換します。実行時に、Java Virtual Machine(JVM)は、コンパイル時間生成バイトコードを実行します。これら2つの期間を通じて、Javaはいわゆるコンピレーションを達成し、どこでも実行しています。
コンピレーション期間中に行われた最適化を試してみましょう。パフォーマンスコストのあるコードを作成します。
public class concatenation {public static void main(string [] args){string username = "andy";文字列age = "24"; string job = "developer";文字列info = username + age + job; System.out.println(info); }}concatenation.javaをコンパイルします。 concatenation.classを取得します
Javac concatenation.java
次に、javapを使用して、コンパイルされたconcatenation.classファイルを逆コンパイルします。 Javap -C連結。 Javapコマンドが見つからない場合は、Javapが環境変数に配置されているディレクトリを追加するか、Javapのフルパスを使用することを検討してください。
17:22:04 -androidyue〜/workspace_adt/strings/src $ javap -c concatenation.java "public class concatenation {public concatenation();コード:0:ALOAD_0 1:Invokespecial#1 // Method Java/Lang/Object。 "<init>" :()v 4:public static void main(java.lang.string [])を返す;コード:0:LDC#2 // STRING ANDY 2:STORE_1 3:LDC#3 // STRING 24 5:STORE_2 6:LDC#4 // STRING DEVELOPER 8:STORE_3 9:NEW#5 // CLASS JAVA/LANG/STRINGBUILDER 12:DUP 13:Invokespecial#6 // Method/Lanan 17:InvokeVirtual#7 // Method Java/Lang/StringBuilder.Append :( ljava/lang/string;)ljava/lang/stringbuilder; 20:ALOAD_2 21:InvokeVirtual#7 // Method Java/Lang/StringBuilder.Append :( ljava/lang/string;)ljava/lang/stringbuilder; 24:Aload_3 25:InvokeVirtual#7 // Method Java/Lang/StringBuilder.Append :( Ljava/Lang/String;)ljava/lang/stringbuilder; 28:InvokeVirtual#8 // Method Java/Lang/StringBuilder.ToString :()Ljava/Lang/String; 31:Store 4 33:GetStatic#9 // Field Java/Lang/System.out:ljava/io/printstream; 36:Aload 4 38:InvokeVirtual#10 // Method Java/io/printstream.println :( ljava/lang/string;)v 41:return}その中で、LDC、ストアなどは、アセンブリ命令と同様のJavaバイトコード命令です。次のコメントは、説明のためにJava関連のコンテンツを使用します。多くのStringBuildersがいることがわかりますが、表示せずにJavaコードでそれらを呼び出します。これは、Javajvmによって行われた最適化です。 Javajvmが文字列スプライシングに遭遇すると、stringbuilderオブジェクトが作成されます。その背後にあるスプライシングは、実際にStringBuilderオブジェクトの付録メソッドを呼び出すことです。このようにして、私たちが心配している問題はありません。
5. JVMの最適化だけに頼っていますか?
JVMは私たちが最適化するのに役立っているので、JVMの最適化だけに依存するだけで十分ですか?もちろん違います。
低パフォーマンスのために最適化されていないコードを見てみましょう
public void ImplicitusestringBuilder(string [] values){string result = ""; for(int i = 0; i <values.length; i ++){result += values [i]; } system.out.println(result);}Javacでコンパイルし、Javapで表示します
public void ImplicitusestringBuilder(java.lang.String []);コード:0:LDC#11 //文字列2:Store_2 3:ICONST_0 4:ISTORE_3 5:ILOAD_3 6:ALOAD_1 7:ARRAYLENGTH 8:IF_ICMPGE 38 11:NEW#5 //クラスJava/Lang/StringBuilder 14:Dup 15:Invokessial#6 //方法java/lang/stringbuilder。 "<init>" :()v 18:aload_2 19:invokevirtual#7 // method java/lang/stringbuilder.append:(ljava/lang/string;)ljava/lang/stringbuilder; 22:ALOAD_1 23:ILOAD_3 24:AALOAD 25:InvokeVirtual#7 // Method Java/Lang/StringBuilder.Append:(Ljava/Lang/String;)ljava/lang/stringbuilder; 28:InvokeVirtual#8 // Method Java/Lang/StringBuilder.ToString :()Ljava/Lang/String; 31:Store_2 32:IINC 3、1 35:GOTO 5 38:GetStatic#9 // Field Java/Lang/System.out:ljava/io/printStream; 41:Aload_2 42:InvokeVirtual#10 // Method Java/io/printStream.println :( ljava/lang/string;)v 45:return
その中に8:if_icmpge 38および35:goto 5がループを形成します。 8:IF_ICMPGE 38は、JVMオペランドスタックの整数比較が(i <values.lengthの逆の結果)以上である場合、38行38(System.out)にジャンプすることを意味します。 35:GOTO 5は、5行目に直接ジャンプすることを意味します。
しかし、ここでは、StringBuilderオブジェクトの作成がループ間で発生するという非常に重要なことがあります。つまり、ループが複数のStringBuilderオブジェクトを作成する回数は、明らかに良くありません。裸の低レベルコード。
わずかに最適化して、品質を即座に改善します。
public void reblicityestringbuilder(string [] values){stringbuilder result = new StringBuilder(); for(int i = 0; i <values.length; i ++){result.append(values [i]); }}対応するコンパイルされた情報
11:Aload_1 12:ArrayLength 13:if_icmpge 30 16:aload_2 17:aload_1 18:iload_3 19:aaload 20:invokevirtual#7 // method/lang/stringbuilder.append:(ljava/lang/string;)ljava/lang/stringbuilder; 23:POP 24:IINC 3、1 27:goto 10 30:return
上記からわかるように、13:if_icmpge 30および27:goto 10はループループを形成しますが、0:新しい#5はループの外側にあるため、StringBuilderは複数回作成されません。
一般的に、ループ本体のストリングビルダーの暗黙的または明示的な作成を避けるようにする必要があります。したがって、コードがどのようにコンパイルされ、どのように内部で実行されるかを理解している人は、比較的高いコードレベルを持っています。
6。結論
ほとんどの場合、stringbuffer> string
Java.lang.StringBufferは、変数文字のスレッドセーフシーケンスです。文字列のような文字列バッファーですが、変更できません。いつでも特定の一連の文字が含まれていますが、シーケンスの長さとコンテンツは、一部のメソッド呼び出しによって変更できます。文字列バッファーは、マルチスレッドのためのプログラムで安全に使用できます。また、これらのメソッドは必要に応じて同期することができるため、特定のインスタンスでのすべての操作は、関係する各スレッドによって行われたメソッド呼び出しの順序と一致するシリアル順序で発生するようです。
StringBufferの主な操作は、あらゆるタイプのデータを受け入れるために過負荷にすることができる追加および挿入メソッドです。各メソッドは、指定されたデータを文字列に効果的に変換し、その文字列の文字を文字列バッファーに追加または挿入できます。追加方法は、常にこれらの文字をバッファの最後に追加します。挿入方法は、指定されたポイントに文字を追加します。
たとえば、zが現在のコンテンツが「start」である文字列バッファオブジェクトを指す場合、このメソッドはz.append( "le")を呼び出します。 Z.INSERT(4、 "LE")は、「スターレット」を含むように文字列バッファーを変更します。
ほとんどの場合、stringbuilder> stringbuffer
Java.lang.StringBuilder Java 5.0では、可変文字シーケンスが新しくなっています。このクラスは、StringBuffer互換のAPIを提供しますが、同期することは保証されていないため、使用法のシナリオは単一のスレッドです。このクラスは、文字列バッファーが単一のスレッドで使用される場合(これは一般)、StringBufferの単純な代替品になるように設計されています。可能であれば、ほとんどの実装ではStringBufferよりも速いため、このクラスを最初に取ることをお勧めします。両方の使用方法は基本的に同じです。