String
、StringBuffer
、およびStringBuilder
を比較するリアルタイムの状況を教えてください。
可変性の違い:
String
はimmutableです。値を変更しようとすると、別のオブジェクトが作成されますが、StringBuffer
とStringBuilder
はmutableであるため、値を変更できます。
スレッドセーフの違い:
StringBuffer
とStringBuilder
の違いは、StringBuffer
がスレッドセーフであることです。そのため、アプリケーションを単一のスレッドでのみ実行する必要がある場合は、StringBuilder
を使用することをお勧めします。 StringBuilder
は、StringBuffer
よりも効率的です。
状況:
String
オブジェクトは不変であるため、文字列が変更されない場合はStringクラスを使用します。StringBuilder
を使用するだけで十分です。StringBuffer
が同期であるため、スレッド変数を使用できるため、StringBuffer
を使用します。String
を使用します。 String
から新しい文字シーケンスを取得すると、CPU時間またはメモリのいずれかで許容できないパフォーマンスの低下が生じる場合があります(データがコピーされないため、サブストリングを取得することはCPU効率的ですが、これは潜在的にはるかに大量のデータが割り当てられたままになる可能性があることを意味します)。StringBuilder
は、通常、複数の文字シーケンスを連結するために、可変文字シーケンスを作成する必要がある場合に使用します。StringBuffer
を使用しますが、StringBuilder
を使用しますが、基になる文字列への変更を同期する必要がある場合(複数のスレッドが文字列バッファーの読み取り/変更を行うため)。例を参照してください here 。
基本:
String
は不変のクラスであり、変更できません。 StringBuilder
は、追加、変更、削除、および最終的にString
に変換できる可変クラスです。StringBuffer
は、StringBuilder
の元の同期バージョンです。
オブジェクトにアクセスするスレッドが1つしかないすべての場合に、StringBuilder
を選択する必要があります。
詳細:
また、StringBuilder/Buffers
は魔法ではなく、単にバッキングオブジェクトとして配列を使用するだけであり、配列がいっぱいになったときに配列を再割り当てする必要があることに注意してください。 .append()
が呼び出されるたびにサイズを常に変更する必要のない、元々十分な大きさのStringBuilder/Buffer
オブジェクトを作成してください。
サイズ変更は非常に退化する可能性があります。基本的に、拡張する必要があるたびに、バッキング配列のサイズを現在のサイズの2倍に変更します。これにより、StringBuilder/Buffer
クラスが大きくなり始めると、大量のRAMが割り当てられ、使用されなくなる可能性があります。
JavaでString x = "A" + "B";
は舞台裏でStringBuilder
を使用します。そのため、単純なケースでは、自分で宣言するメリットはありません。ただし、4k未満などの大きなString
オブジェクトを構築する場合、StringBuilder sb = StringBuilder(4096);
の宣言は、連結や デフォルトコンストラクター (16文字のみ)を使用するよりもはるかに効率的です。 String
が10k未満になる場合は、コンストラクターで10kに初期化して安全にします。しかし、10kに初期化されている場合、10kを超える1文字を書き込むと、再割り当てされて20k配列にコピーされます。したがって、高よりも初期化する方が低よりも優れています。
自動サイズ変更の場合、17番目の文字で補助配列が再割り当てされて32文字にコピーされ、33番目の文字でこれが再び発生し、再割り当てされて配列を64文字にコピーします。これがどのようにlotsに縮退し、最初にStringBuilder/Buffer
の使用を避けようとしているのかを見ることができます。
これは、AbstractStringBuilderのJDK 6ソースコードからのものです。
void expandCapacity(int minimumCapacity) {
int newCapacity = (value.length + 1) * 2;
if (newCapacity < 0) {
newCapacity = Integer.MAX_VALUE;
} else if (minimumCapacity > newCapacity) {
newCapacity = minimumCapacity;
}
value = Arrays.copyOf(value, newCapacity);
}
ベストプラクティスは、String
の大きさがすぐにわからないが推測できる場合は、StringBuilder/Buffer
を必要以上に大きく初期化することです。必要以上にわずかに多くのメモリを割り当てると、多くの再割り当てやコピーよりも優れたものになります。
また、StringBuilder/Buffer
をString
で初期化することに注意してください。これは、ほとんどの場合、回避しようとしている縮退した再割り当てとコピーサイクルを開始するだけのString + 16文字のサイズを割り当てます。以下は、Java 6ソースコードから直接抜粋したものです。
public StringBuilder(String str) {
super(str.length() + 16);
append(str);
}
偶然作成しておらず、呼び出されたコンストラクターを制御できないStringBuilder/Buffer
のインスタンスになった場合、縮退した再割り当てとコピーの動作を回避する方法があります。 .ensureCapacity()
を呼び出して、結果のString
が収まるようにします。
代替案:
ちょうどメモとして、本当にheavyString
の構築と操作を行う場合、 Ropes と呼ばれるよりパフォーマンス指向の代替があります=。
別の代替方法は、ArrayList<String>
をサブクラス化してStringList
実装を作成し、カウンターを追加してすべての.append()
およびリストの他の突然変異操作の文字数を追跡し、.toString()
をオーバーライドして、必要な正確なサイズのStringBuilder
を作成することですリストを介して出力を作成すると、そのStringBuilder
をインスタンス変数にして、.toString()
の結果を「キャッシュ」し、何か変更があった場合にのみ再生成することができます。
また、固定形式の出力を作成する場合はString.format()
を忘れないでください。これは、コンパイラが改善するため最適化できます。
連結の意味ですか?
実世界の例:他の多くの文字列から新しい文字列を作成したい。
たとえば、メッセージを送信するには:
ひも
String s = "Dear " + user.name + "<br>" +
" I saw your profile and got interested in you.<br>" +
" I'm " + user.age + "yrs. old too"
StringBuilder
String s = new StringBuilder().append.("Dear ").append( user.name ).append( "<br>" )
.append(" I saw your profile and got interested in you.<br>")
.append(" I'm " ).append( user.age ).append( "yrs. old too")
.toString()
または
String s = new StringBuilder(100).appe..... etc. ...
// The difference is a size of 100 will be allocated upfront as fuzzy Lollipop points out.
StringBuffer(構文はStringBuilderとまったく同じで、効果は異なります)
約
StringBuffer
vs. StringBuilder
前者は同期され、後は同期されません。
したがって、単一のスレッドで複数回呼び出すと(ケースの90%)、StringBuilder
は、スレッドロックを所有しているかどうかを確認するために停止しないため、muchより高速に実行されます。
したがって、StringBuilder
を使用することをお勧めします(もちろん、同時に複数のスレッドがそれにアクセスしている場合を除き、これはまれです)
String
連結(+演算子を使用)は、コンパイラーによって最適化され、その下でStringBuilder
を使用するため、長老では心配する必要がなくなりますJavaの時代、これは、すべての連結が新しいStringオブジェクトを作成したため、すべての犠牲を払って避けるべきだと誰もが言うものでした。最近のコンパイラーではこれを行わなくなりましたが、「古い」コンパイラーを使用する場合に備えて、代わりにStringBuilder
を使用することをお勧めします。
編集
好奇心が強い人のために、これはコンパイラがこのクラスのために行うことです:
class StringConcatenation {
int x;
String literal = "Value is" + x;
String builder = new StringBuilder().append("Value is").append(x).toString();
}
javap -c StringConcatenation
Compiled from "StringConcatenation.Java"
class StringConcatenation extends Java.lang.Object{
int x;
Java.lang.String literal;
Java.lang.String builder;
StringConcatenation();
Code:
0: aload_0
1: invokespecial #1; //Method Java/lang/Object."<init>":()V
4: aload_0
5: new #2; //class Java/lang/StringBuilder
8: dup
9: invokespecial #3; //Method Java/lang/StringBuilder."<init>":()V
12: ldc #4; //String Value is
14: invokevirtual #5; //Method Java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
17: aload_0
18: getfield #6; //Field x:I
21: invokevirtual #7; //Method Java/lang/StringBuilder.append:(I)Ljava/lang/StringBuilder;
24: invokevirtual #8; //Method Java/lang/StringBuilder.toString:()Ljava/lang/String;
27: putfield #9; //Field literal:Ljava/lang/String;
30: aload_0
31: new #2; //class Java/lang/StringBuilder
34: dup
35: invokespecial #3; //Method Java/lang/StringBuilder."<init>":()V
38: ldc #4; //String Value is
40: invokevirtual #5; //Method Java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
43: aload_0
44: getfield #6; //Field x:I
47: invokevirtual #7; //Method Java/lang/StringBuilder.append:(I)Ljava/lang/StringBuilder;
50: invokevirtual #8; //Method Java/lang/StringBuilder.toString:()Ljava/lang/String;
53: putfield #10; //Field builder:Ljava/lang/String;
56: return
}
5〜27の行は、「リテラル」という名前の文字列用です。
31〜53の行は、「builder」という名前の文字列用です。
違いはありません。正確に同じコードが両方の文字列に対して実行されます。
文字列
String class
は文字列を表します。 "abc"
などのJavaプログラムのすべての文字列リテラルは、このクラスのインスタンスとして実装されます。
文字列オブジェクトはimmutableであり、一度作成されると変更できません。 (文字列は定数です)
コンストラクターまたはメソッドを使用して文字列が作成された場合、それらの文字列はHeap Memoryにも保存されますas SringConstantPool
ただし、プールに保存する前に、intern()
メソッドを呼び出して、equalsメソッドを使用してプール内の同じコンテンツでオブジェクトの可用性を確認します。 プールで文字列コピーが利用可能な場合、参照を返します。それ以外の場合、Stringオブジェクトがプールに追加され、参照が返されます。
+
)、および他のオブジェクトの文字列への変換に特別なサポートを提供します。文字列の連結は、StringBuilder(またはStringBuffer)クラスとそのappendメソッドを通じて実装されます。String heapSCP = new String("Yash");
heapSCP.concat(".");
heapSCP = heapSCP + "M";
heapSCP = heapSCP + 777;
// For Example: String Source Code
public String concat(String str) {
int otherLen = str.length();
if (otherLen == 0) {
return this;
}
int len = value.length;
char buf[] = Arrays.copyOf(value, len + otherLen);
str.getChars(buf, len);
return new String(buf, true);
}
文字列リテラルはStringConstantPool
に保存されます。
String onlyPool = "Yash";
StringBuilder および StringBufferは変更可能な文字列です。つまり、これらのオブジェクトの値を変更できます。 StringBufferにはStringBuilderと同じメソッドがありますが、StringBufferの各メソッドは同期されているため、スレッドセーフです。
StringBufferおよびStringBuilderデータは、new演算子を使用してのみ作成できます。したがって、それらはヒープメモリに格納されます。
StringBuilderのインスタンスは、複数のスレッドで安全に使用できません。このような同期が必要な場合は、StringBufferを使用することをお勧めします。
StringBuffer threadSafe = new StringBuffer("Yash");
threadSafe.append(".M");
threadSafe.toString();
StringBuilder nonSync = new StringBuilder("Yash");
nonSync.append(".M");
nonSync.toString();
StringBufferとStringBuilderには、replace(int start, int end, String str)
やreverse()
などの特別なメソッドがあります。
NOTE:StringBufferとSringBuilderは
Appendable Interface
の実装を提供するため、可変です。
どちらを使用するか。
値を毎回変更しない場合は、String Class
を使用することをお勧めします。ジェネリックの一部として Comparable<T>
をソートする場合、または値を比較する場合は、String Class
に進みます。
//ClassCastException: Java.lang.StringBuffer cannot be cast to Java.lang.Comparable
Set<StringBuffer> set = new TreeSet<StringBuffer>();
set.add( threadSafe );
System.out.println("Set : "+ set);
StringBuilderを使用するたびに値を変更する場合は、StringBufferよりも高速です。複数のスレッドが値を変更している場合は、StringBufferを使用します。
--------------------------------------------- ------------------------------------- String StringBuffer StringBuilder -------------------------------------------------- -------------------------------- ストレージエリア|定数文字列プールヒープヒープ 変更可能|いいえ(不変)はい(mutable)はい(mutable) スレッドセーフ|はいはいいいえ パフォーマンス|速いとても遅い速い ----------------------------------------- -----------------------------------------
また、StringBuffer
はスレッドセーフですが、StringBuilder
はスレッドセーフではありません。
そのため、さまざまなスレッドがアクセスしているリアルタイムの状況では、StringBuilder
の結果が不確定になる可能性があります。
Java 5以降を使用している場合は、StringBuilder
の代わりにStringBuffer
を使用する必要があります。 APIドキュメントから:
リリースJDK 5の時点で、このクラスは、単一のスレッド
StringBuilder
で使用するために設計された同等のクラスで補足されています。StringBuilder
クラスは、同じ操作をすべてサポートしますが、同期を実行しないため高速であるため、通常はこのクラスよりも優先して使用する必要があります。
実際には、複数のスレッドから同時にこれを使用することはほとんどないため、StringBuffer
が行う同期はほとんどの場合不要なオーバーヘッドです。
個人的には、StringBuffer
の実際の使用はないと思います。文字シーケンスを操作することにより、複数のスレッド間でいつ通信したいのですか?それはまったく役に立たないように聞こえますが、おそらく私はまだ光を見ていません:)
Stringと他の2つのクラスの違いは、Stringが不変であり、他の2つが可変クラスであることです。
しかし、なぜ同じ目的のために2つのクラスがあるのですか?
理由は、StringBuffer
name__はスレッドセーフであり、StringBuilder
name__はスレッドセーフではないからです。 StringBuilder
name__はStringBuffer Api
の新しいクラスであり、JDK5
で導入されました。また、Faster
name__であるため、シングルスレッド環境で作業している場合は常に推奨されます。
詳細については、 http://www.codingeek.com/Java/stringbuilder-and-stringbuffer-a-way-to-create-mutable-strings-in-Java/ を参照してください。
Javaでは、Stringは不変です。不変であるということは、一度ストリングが作成されると、その値を変更できないことを意味します。 StringBufferは可変です。 StringBufferオブジェクトが作成されたら、新しいオブジェクトを作成するのではなく、オブジェクトの値にコンテンツを追加するだけです。 StringBuilderはStringBufferに似ていますが、スレッドセーフではありません。 StingBuilderのメソッドは同期されませんが、他の文字列と比較すると、Stringbuilderが最も速く実行されます。 String、StringBuilder、StringBuffer の違いを実装することで学習できます。