Javaは、文字列を処理するための3つのクラス、それぞれ、文字列、StringBufferのとStringBuilderのを提供します。ただ導入JDK1.5でのStringBuilder。
これらの三つのクラスどのような違いは、それをしませんか?それはどのような彼らの使用シナリオあるのですか?
この記事のコードは、jdk12、jdk12とJDK5にjdk8大きな違いは、特に文字列、StringBufferをとのStringBuilderの実装を実行しています。
ストリングクラスの型と値JDK5のjdk8 []はバイトをCHAR []、jdk12するため、値型です。
JDK5は、JDK6定数プールは、永久世代にあり、Javaヒープの永久的な生成は、2つの完全に別個の領域です。
後でJDK7とするためには、
ソースコードのこれらの三つのクラスを見てみましょう。
Stringクラスのセクション出典:
public final class String
implements java.io.Serializable, Comparable<String>, CharSequence,
Constable, ConstantDesc {
@Stable
private final byte[] value;
public String(String original) {
this.value = original.value;
this.coder = original.coder;
this.hash = original.hash;
}
public native String intern();
Stringクラスは、最終的な修飾子によって変更され、そのStringクラスは、一度作成されたオブジェクトは、変更することができない、不変です。
ストリングクラスのメンバ変数のバイト配列は、この変数の値は、文字列の内容を格納するために使用されている、一度初期化され、最終で修飾され、変更することができません。
Javaは、文字列を作成するには、2つの主な方法を提供します。
//方式1
String str = "123";
//方式2
String str = new String("123");
Java仮想マシンの仕様では、文字列がモード1またはモード2列、それがすでに存在する場合は、文字列定数にプールから見上げ、直接リターン、またはの作成で作成したかどうか、文字列定数プールに格納されている定義しますリターン。
コンパイルしたJavaクラスは、この文字列は定数「こんにちは」、「abc」が遭遇したとき、定常領域は、これらのクラスの定数、クラスのロードされるJavaコンパイラは、文字列は定数文字列定数に追加しますプール。
式を含む文字列定数は、例えば、文字列str =「ABC」+ A、コンパイル時の定常領域に配置されていません
定数プールの最大の効果は、プログラムの実行効率を向上させ、使用する共有されます。
以下のいくつかの例を見てください。
ケース1:
1 String str1 = "123";
2 String str2 = "123";
3 System.out.println(str1 == str2);
上記のコードを実行した結果が真です。
あなたは、コードの最初の行を実行して、今すぐ123個のオブジェクトの文字列定数プールを作成し、変数STR1に割り当てられたとき。
二行目を実行し、定数プール123被写体の存在は、可変オブジェクトSTR2に直接アドレス123を返すことが見出されました。
STR1およびアドレスにSTR2変数のポイントは、彼らが同じオブジェクト、およびtrueにランニングのため、結果です。
「」引用符(およびリテラル前記の通常量)文字列を作成するSTR1を用いて、図から分かるように、コンパイル時に文字列が存在する定数プールがある場合は直接リターンオブジェクトを作成していないか否かを判断します参照;そうでない場合には、バック0009にインスタンスに文字列定数プール参照してインスタンスを作成します。
ケース2:
1 String str1 = new String("123");
2 String str2 = new String("123");
3 String str3 = new String(str2);
4 System.out.println((str1==str2));
5 System.out.println((str1==str3));
6 System.out.println((str3==str2));
上記のコードの結果が実行されます
false
false
false
実行されたとき、図形、コードの最初の行から分かるように、2つのオブジェクト、定数プールに格納された文字列を作成し、スタックの存在は、スタック0009に格納されたオブジェクトへの参照があります。
二行目を実行するときに、ヒープ内の既存の文字列定数プール「123」のオブジェクトは、これだけの文字列オブジェクトを作成し、対象点アドレスへのオブジェクトの定数プール「123」番地、スタック一方オブジェクト参照STR2、作成されたオブジェクトのアドレスヒープへの参照を作成します。
ヒープ内のコードの3行目の実装では、メモリアドレスを実行するために可変STR2のメモリアドレスを指す文字列オブジェクトを作成します。
新しい方法によって作成されたStringオブジェクトは、文字列定数プール格納されたオブジェクトのヒープメモリに新しいスペースを開きます。
動作は比較== 2個の排他的なメモリアドレス一致であるか否かをオブジェクトについては、上記コードの実行の結果は偽です。
ケース3:
//这行代码编译后的效果等同于String str1 = "abcd";
String str1 = "ab" + "cd";
String str2 = "abcd";
System.out.println((str1 == str2));
真:上記のコードの実装の結果。
常時接続を含む文字列も一定作成された使用、コンパイラは、クラスはもちろん、文字列定数プールはすでにその文字列が存在するかどうかを確認する必要があり、文字列定数プールに直接ロードされる期間を決定することができます。
ケース4:
String str2 = "ab"; //1个对象
String str3 = "cd"; //1个对象
String str4 = str2 + str3 + “1”;
String str5 = "abcd1";
System.out.println((str4==str5));
偽:上記のコードの実装の結果。
「+」は、文字列に接続されているときに変数が含まれ、変数の値は、実行時に決定されるべきです。
あなたは文字列の連結は、appendメソッドのCONCATENATE文字列を呼び出すことによって、ヒープのJVM StringBuilderオブジェクトを生成する仮想マシンのjdk8以前のバージョンを使用している場合は、toStringメソッドStringBuilderの最後の呼び出しスタックは、JVMの最後の文字列オブジェクトを生成します。
StringBuilderを介して実装する際、バイトコードを見て、あなたは「+」文字列連結のjdk8バージョンの前に知ることができます。以下に示すように、バイトコードを見ることで、知ることができます。
仮想マシンの新しいバージョンをjdk9使用している場合や、呼び出している仮想マシンは、invokedynamicの文字列の連結を来て、ヒープに保存されました。バイトコードは次のよう:
返された結果が偽であるので、STR4文字列定数プール内のオブジェクト、ヒープ上STR5オブジェクトなので、彼らは、同じオブジェクトではありません。
ケース5:
String s5 = new String(“2”) + new String(“3”);
ケース4と同じ、新しいString(「2」)は文字列を作成するだけでなく、実行時にオブジェクトのメモリアドレスを決定するために、そして同じの4例です。
ケース6:
final String str1 = "b";
String str2 = "a" + str1;
String str3 = "ab";
System.out.println((str2 == str3));
上記のコードの実行結果はtrueです。
STR1の変数は、それが直接文字列定数プール、上記のコードと同様の効果に、コンパイル時に決定され、定数です。
String str2 = "a" + "b";
String str3 = "ab";
System.out.println((str2 == str3));
ストリングクラスにはインターン()メソッドを呼び出して、文字列に文字列の例は、スタック定数プールに配置されます。
事例7:
String str2 = "ab";
String str3 = "cd";
String str4 = str2 + str3 + "1";
str4.intern();
String str5 = "abcd1";
System.out.println((str4==str5));
真:上記のコードの実装の結果。str4.intern()メソッドを呼び出した後STR4文字列定数プールを置いて、同じことがSTR5インスタンスですします。
ソースコードのStringBufferの部分:
public final class StringBuffer
extends AbstractStringBuilder
implements java.io.Serializable, Comparable<StringBuffer>, CharSequence
{
ソースコードのStringBuilderの一部:
public final class StringBuilder
extends AbstractStringBuilder
implements java.io.Serializable, Comparable<StringBuilder>, CharSequence
{
可視のStringBufferとStringBuilderのはAbstractStringBuilderクラスを継承します。
ソースカテゴリAbstractStringBuilder:
abstract class AbstractStringBuilder implements Appendable, CharSequence {
/**
* The value is used for character storage.
*/
byte[] value;
AbstractStringBuilder部材はまた、最終的な変数が変更されないと、それは変更することができ、バイト配列変数値、文字列を格納された変数の値を有し、これは文字列の最大の違いです。
appendメソッドを呼び出すときに、動的にバイト配列変数値のサイズを大きくします。
たStringBufferとStringBuilderの機能は同じで、直接使用+文字列連結するので、その後、JVMは複数の文字列オブジェクトを作成するので、オーバーヘッドの一定量、接続文字列内のJavaの効率を改善することです。文字列を保持するために使用されるバイト配列を追加する必要がAbstractStringBuilder、バイト配列、すなわち大きな再適用期間、現在の文字列の長さアペンドchar配列容量、バイト配列の動的拡張を超える場合、初期サイズを有しています各再応用モードメモリ空間はここで二度、現在のアプリケーションは、メモリ空間の使用を必要とするよりも大きくなるように、メモリ空間、および新しい配列ビュート現在の場所にコピーされ、メモリの再配置オーバーヘッドとしてコピーは、比較的大きいです。
クラスStringBufferのメソッドの前でのStringBufferとStringBuilderのStringBufferの間の最大の違いスレッドセーフですが、StringBuilderのは、スレッドセーフではありません、そのソースからの2つのクラスが知ることができますが、修飾子を同期しています。
新しい値が保存のために再オープンしたメモリアドレスを説明する場合には割り当てたら、文字列は、インスタンス化後に変更またはすることはできません。
そのようなインサートを変更すると、元のオブジェクト・ストレージのメモリアドレスに連続運転を除いて文字列値を追加し、オーバーヘッドリソースを減少させるような方法を使用している間のStringBufferとStringBuilderのクラス。
概要:
1、頻繁に「+」の文字スプライシング操作を使用しては、appendメソッドのStringBufferとStringBuilderクラスの実装に置き換えます。
図2に示すように、マルチスレッド環境を使用して、スプライシングのStringBuffer文字列操作の多数、スレッドセーフのStringBuffer。
3、シングルスレッド環境下で動作し、文字列の連結用のStringBuilderの多くは、StringBuilderのは、スレッドセーフではありません。