0

Java の String オブジェクトが不変であることは誰もが知っています。これは、基本的に、aString オブジェクトを別の String オブジェクトと連結すると、たとえばb、インプレース連結ではなく、まったく新しい String オブジェクトが作成されることを意味します。

ただし、最近、連結演算子がコンパイラによってインスタンスに置き換えられることを伝える SO に関するこの質問を読みました。+StringBuilder

この時点で、私が知り、考える限り、StringBuilderオブジェクトは内部構造のために変更可能であるため、少し混乱します。この場合、これは本質的に Java の String オブジェクトを可変にするのではないでしょうか?

4

3 に答える 3

3

あまり。

実際の String は依然として不変ですが、コンパイル時に、JVM は、追加の String オブジェクトの作成を StringBuilder に置き換えることができるいくつかの状況を検出できます。

したがって、String を宣言しaて別の String と連結しても、aオブジェクトは変更されませんが (不変であるため)、JVM は連結を StringBuilder のインスタンス化に置き換え、両方の String を Builder に追加し、最後にこれを最適化します。結果の文字列を割り当てます。

あなたが持っているとしましょう:

String a = "banana";
String d = a + "123" + "xpto";

JVM がこれを最適化する前は、基本的に、非常に単純なもののために比較的多数の文字列を作成していました。つまり、次のようになります。

  • 文字列
  • 文字列「123」
  • 文字列「xpto」
  • 文字列 a + "123"
  • 文字列 a+"123"+"xpto"

連結を StringBuilder に変換する最適化により、JVM は連結の中間結果を作成する必要がなくなるため、個々の文字列と結果の文字列だけが必要になります。

これは基本的にパフォーマンス上の理由から行われますが、注意しないと、特定の状況でこれに大きなペナルティを支払うことになることに注意してください。例えば:

String a = "";
for(String str: listOfStrings){
    a += str;
}

このようなことを行っていた場合、各反復で JVM は新しいStringBuilder をインスタンス化しlistOfStringsます。要素が多数ある場合、これは非常にコストがかかります。この場合、StringBuilder連結する代わりに、ループ内で a を明示的に使用して追加を行う必要があります。

于 2013-04-14T18:11:02.020 に答える
2

文字列は不変オブジェクトです。別の String と連結すると、新しいオブジェクトになります。覚えておいてください - 既存の文字列を変更するのではなく、新しい文字列を作成するだけです。

于 2013-04-14T18:14:45.860 に答える
1

文字列は本当に不変です。コンパイラは を含むコードを生成する場合がありますがStringBuilder、これは単なる最適化であり、(パフォーマンスは別として) コードの動作を変更しません。変更を観察できるケースがあった場合 (たとえば、中間結果の 1 つへの参照を保持することによって)、コンパイラは、その中間参照に対して不変の文字列を提供する方法で最適化する必要があります。

では、StringBuilder直接違いを確認できなくても、内部で使用されている場合でも、可変性が関与していることを意味するのではないでしょうか? ええ、そうです。でも、よく考えてみると、PC のすべての RAM は変更可能です。不変オブジェクトのメモリはガベージ コレクターによって移動できますが、これには間違いなくミューテーションも含まれます。最後に、プログラマーとしてのあなたにとって重要なことは、この突然変異があなたから隠されていることであり、あなたのプログラムが期待どおりに動作するという大きな約束を得るということです。 RAM の故障など、重大な問題が発生した場合)。

于 2013-04-14T18:23:44.680 に答える