ホームページ  >  記事  >  バックエンド開発  >  String StringBuffer StringBuilder区别

String StringBuffer StringBuilder区别

巴扎黑
巴扎黑オリジナル
2016-12-20 15:49:411306ブラウズ

String 文字列定数
StringBuffer 文字列変数 (スレッド セーフ)
StringBuilder 文字列変数 (非スレッド セーフ)
簡単に言うと、String 型と StringBuffer 型の主なパフォーマンスの違いは、String は不変オブジェクトであるため、どのオブジェクトでもString 型を変更するたびに、実際には新しい String オブジェクトを生成し、その新しい String オブジェクトを指すポインタを指定するのと同じことになります。そのため、内容が頻繁に変更される文字列には String を使用しないことをお勧めします。オブジェクトが生成されると、システムに悪影響を及ぼします。特に、メモリ内に参照されていないオブジェクトが多すぎると、JVM の GC が動作し始め、速度がかなり遅くなります。
StringBuffer クラスを使用する場合、結果はそれぞれ異なります。新しいオブジェクトを生成してオブジェクト参照を変更するのではなく、StringBuffer オブジェクト自体を操作します。したがって、一般に、特に文字列オブジェクトが頻繁に変更される場合には、StringBuffer を使用することをお勧めします。一部の特殊なケースでは、String オブジェクトの文字列連結は、実際には JVM によって StringBuffer オブジェクトの連結として解釈されるため、このような場合、String オブジェクトの速度が StringBuffer オブジェクトの速度よりも遅くなることはなく、特に次の文字列オブジェクトはこのうち、String の効率は StringBuffer よりもはるかに高速です。 ").append(" test");
String S1 オブジェクトの生成速度が速すぎることに驚くでしょうが、現時点では StringBuffer には速度の点でまったく利点がありません。実際、これは JVM のトリックであり、JVM から見ると、この
String S1 = “This is just a” + “simple” + “test” は次のようになります。簡単なテストですので、もちろん時間はかかりません。ただし、ここで注意すべき点は、文字列が別の String オブジェクトからのものである場合、速度はそれほど速くないということです。たとえば、次のようになります。 = "test";
String S1 = S2 +S3 + S4;
このとき、JVM は元の方法で実行します

StringBuffer
StringBuffer
Java.lang。文字列。 String に似た文字列バッファですが、変更できません。任意の時点で特定の文字シーケンスが含まれていますが、そのシーケンスの長さと内容は特定のメソッド呼び出しによって変更できます。
文字列バッファは複数のスレッドで安全に使用できます。これらのメソッドは必要に応じて同期できるため、特定のインスタンスに対するすべての操作が、関連する各スレッドによって行われるメソッド呼び出しの順序と一致するシリアル順序で発生するように見えます。
StringBuffer の主な操作は追加メソッドと挿入メソッドであり、これらはオーバーロードしてあらゆる種類のデータを受け入れることができます。各メソッドは、指定されたデータを文字列に効果的に変換し、その文字列の文字を文字列バッファーに追加または挿入します。 append メソッドは常にこれらの文字をバッファーの末尾に追加し、insert メソッドは指定された位置に文字を追加します。
たとえば、z が現在の内容が "start" である文字列バッファ オブジェクトを参照している場合、このメソッドで z.append("le") を呼び出すと、文字列バッファには "startle" が含まれますが、z.insert(4 , "le") は、文字列バッファーを変更して "starlet" を含めます。
ほとんどの場合 StringBuilder > StringBuffer
java.lang.StringBuilde
java.lang.StringBuilder 変数文字シーケンスは 5.0 の新機能です。このクラスは StringBuffer 互換の API を提供しますが、同期は保証されません。このクラスは、文字列バッファーが単一スレッドによって使用される場合 (これが一般的な状況です)、StringBuffer のドロップイン置換として設計されています。ほとんどの実装では StringBuffer よりも高速であるため、可能であればこのクラスを優先することをお勧めします。どちらの方法も基本的には同じです。
================================================ === ========================
Stringクラスの詳細説明
1. Stringクラスはfinalクラスなので継承できません。
2. String クラスの本質は文字配列 char[] であり、その値は変更できません。 PRivate Final char value[]; 次に、String クラスの API ドキュメントを開くと、次のことがわかります:
3. String クラスのオブジェクトを作成するには、たとえば String x = "abc" を直接指定します。 , 「abc」は String オブジェクトを表します。そして、x は「abc」オブジェクトのアドレスであり、「abc」オブジェクトへの参照として

とも呼ばれます。
4. 文字列オブジェクトは「+」を使用して連結できます。連結後、新しい文字列が生成されます。後述する concat() を使用して連結することもできます。
6. Java は実行中に文字列プールを維持します。JavaDoc の翻訳は「文字列バッファ」として非常に曖昧です。文字列プールは、実行時に生成されるさまざまな文字列を保存するために使用されます

また、プール内の文字列の内容は繰り返されません。このバッファプールは一般のオブジェクトには存在せず、作成されたオブジェクトはメソッドのスタック領域にのみ存在します。


5. 文字列を作成するには多くの方法があり、次の 3 つのカテゴリにまとめられます。
最初に、新しいキーワードを使用して文字列を作成します (例: String s1 = new String("abc"); 2 番目に次のように指定します)。それを直接。たとえば、 String s2 = "abc";
3 番目に、連結を使用して新しい文字列を生成します。たとえば、 String s3 = "ab" + "c";

2. String オブジェクトの作成

String オブジェクトの作成も、その原理を理解することが重要です。
原則 1: 何らかのメソッドを使用して文字列オブジェクト s を作成する場合、Java ランタイム (実行中の JVM) はこれを受け取り、プール内に文字列 s を作成します。それ以外の場合は、それをプールに追加しません。

原則 2: Java では、new キーワードを使用してオブジェクトを作成する限り、新しいオブジェクトは確実に (ヒープ領域またはスタック領域に) 作成されます。

原則 3: 直接指定または純粋な文字列連結を使用して String オブジェクトを作成する場合、String プール内の文字列のみがチェックおよび維持されます。プール内に文字列がない場合は、プール内に文字列を作成します。
!ただし、String オブジェクトがスタック領域に作成されることはありません。

原則 4: 変数を含む式を使用して String オブジェクトを作成すると、String プールがチェックおよび維持されるだけでなく、スタック領域に String オブジェクトも作成されます。

さらに、String の intern() メソッドは、パブリック ネイティブ String intern() として定義されるローカル メソッドです。intern() メソッドの値は、開発者が

String プールに集中できるようにすることです。 intern メソッドが呼び出されたときに、この String オブジェクトと等しい文字列 (equals(Object) メソッドによって決定される) がプールに既に含まれている場合は、プール内の文字列

が返されます。それ以外の場合、この String オブジェクトはプールに追加され、この String オブジェクトへの参照が返されます。

3. 不変クラス
不変文字列には大きな利点があります。それは、コンパイラが文字列を共有するように設定できることです。
不変 String クラスには、共有参照ではないという重要な利点があります。

以上です。効率を向上させるために、JAVA は String 型に対して特別な処理を実行します。つまり、string 型の変数を定義するには 2 つの方法があります。
string name= "tom ";
string name =new string( "tom ")
最初のメソッドを使用する場合は、文字列プールを使用します。
2 番目のメソッドを使用する場合は、オブジェクトを宣言する通常の方法です。
2 番目のメソッドを使用する場合は、一方向です。そうすると、内容も "tom" である文字列を宣言すると、メモリを再割り当てせずに文字列プール内の元のメモリが使用されます。つまり、 string saname = "tom " は、同じメモリを指すことになります

。さらに、文字列型が不変であるという問題について:
文字列型は不変です。つまり、name = "madding " などの文字列オブジェクトを変更したい場合です。
その場合、仮想マシンは元の文字列を変更しません。オブジェクトを作成しますが、新しい文字列オブジェクトを生成し、name がそれを指すようにします。元の「tom」にそれを参照するオブジェクトがない場合、仮想マシンのガベージ コレクション メカニズムがそれを受け取ります。
これで効率が上がると言われています! ! !
================================================ === ========================最終 StringBuffer a = new StringBuffer("111");
final StringBuffer b = new StringBuffer("222") );
a=b;//この文はコンパイルを通過しません
final StringBuffer a = new StringBuffer("111");
a.append("222");// コンパイルは通過します
Final は、参照される「値」(つまり、メモリ アドレス) にのみ適用されます。これにより、参照は最初に指されたオブジェクトのみを指すように強制され、そのポインティングを変更するとコンパイル時エラーが発生します。それが指すオブジェクトの変更に関しては、final は責任を負いません。

文字列定数プールの問題の 4 つの例
以下は、いくつかの一般的な例の比較分析と理解です:

[1]
String a = "a1";
System.out .println((a == b)); //結果 = true
String a = "a";
System.out.println((a == b)) ; //結果 = true
String a = "a" + 3.4; //結果 = true
分析: JVM は、プログラムのコンパイル中に文字列定数の「+」接続を接続後の値に最適化します。例として「a」 + 1 を取り上げます。コンパイラーの最適化後、それはすでにクラス内で a1 です。文字列定数の値はコンパイル中に決定されるため、上記のプログラムの最終結果は true になります。

[2]
文字列 a = "ab";
文字列 b = "a" + bb; //結果 = false
分析: 文字列参照の場合、JVM は文字列の "+" 接続に文字列参照を持ち、プログラムのコンパイル中に参照の値を決定できません。つまり、コンパイラは "a" + bb を使用できません。最適化では、プログラム実行中に b に接続した後の新しいアドレスのみを動的に割り当てて割り当てます。したがって、上記のプログラムの結果は false になります。

[3]
文字列 a = "ab";
文字列 b = "a" + bb; //結果= true
分析: [3] との唯一の違いは、bb 文字列が最終的に変更されることです。最終的に変更される変数の場合、コンパイル時に定数値のロ​​ーカル コピーに解析され、独自の定数プールに格納されます。バイトコードストリームに埋め込まれます。
この時の「a」+bbと「a」+「b」の効果は同じです。したがって、上記のプログラムの結果は true になります。

[4]
文字列 a = "ab";
文字列 b = "a" + bb; //結果= false
private static String getBB() { return "b"; }
分析: JVM は、プログラムの実行中にメソッドを呼び出した後にのみ、文字列参照 bb の値を決定できません。 a" は動的に接続してアドレスを b に割り当てるために使用されるため、上記のプログラムの結果は false になります。

上記の 4 つの例から結論付けることができます:

String s = "a" + "b" + "c";

String a = "a"; と同等です。 String b = "b";
String c = "c";
String s = a + b + c;
これは異なり、最終的な結果は次のようになります:

StringBuffer temp = new StringBuffer(); append(a).append(b).append(c);
String s = temp.toString();
上記の分析結果から、String が接続演算子 (+) を使用する理由を推測するのは難しくありません。は非効率なので、コードは次のようになります。

public class Test {
public static void main(String args[]) {
String s = null;
for(int i = 0; i }
}
+ を実行するたびに StringBuilder オブジェクトが生成され、追加後に破棄されます。次回ループが到着すると、StringBuilder オブジェクトが再生成され、文字列が追加され、このループは最後まで継続します。 StringBuilder オブジェクトを追加に直接使用すると、オブジェクトの作成と破棄の N - 1 回を節約できます。したがって、ループ内で文字列の連結が必要なアプリケーションでは、通常、追加操作に StringBuffer または StringBulider オブジェクトが使用されます。

Stringオブジェクトのインターンメソッドの理解と分析
public class Test4 {
private static String a = "ab";
public static void main(String[] args){
String s1 = "a"; " b";
String s = s1 + s2;
System.out.println(s == a);//false
System.out.println(s.intern() == a);//true
}
}
ここでの Java の使用は、常にプールの問題です。 s1+s2 操作の場合、実際には新しいオブジェクトがヒープ内に作成され、s はこの新しいオブジェクトの内容をヒープ領域に保存するため、s と a の値は等しくありません。 s.intern() メソッドを呼び出すと、定数プール内の s のアドレス値を返すことができます。a の値は定数プールに格納されているため、s.intern と a の値は等しくなります。

声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。