Java では、文字列は String クラスのオブジェクトとしてメモリに保存されます。
Java プログラムにメモリが割り当てられると、JVM (Java 仮想マシン) は割り当てられたメモリを 2 つの部分に分割します。 1 つの部分はスタック、もう 1 つの部分はヒープです。ヒープ メモリでは、Java は一部のメモリを割り当てます。特にリテラルに対して、そのメモリは文字列定数プール (SCP) と呼ばれます。 SCP は、ヒープ内の事前定義された領域です。文字列プールは、Java ランタイム用のスペースを大幅に節約するのに役立ちます。 String クラスは SCP を使用して一意の文字列リテラルを保存します。
スタック メモリには、変数、変数参照、またはオブジェクトへの参照が保存されます。
ヒープメモリには、動的に割り当てられたすべてのオブジェクトが格納されます。オブジェクトにメモリを割り当てるには、新しいキーワードを使用します。
文字列オブジェクトを作成するには 2 つの方法があります。
文字列 str1 = “MyString”;
文字列リテラルを作成するときは常に、JVM はまず文字列リテラルが文字列定数プールにすでに存在するかどうかを確認します。利用できない場合は、SCP.
に新しい文字列リテラルが作成されます。上の図では、str1 は SCP の「MyString」を指します。新しく作成された文字列リテラルの処理方法は次のとおりです。
文字列 str2 = 新しい文字列(“MyString”); //新しいキーワードを使用して文字列クラスをインスタンス化します
新しいキーワードを使用して文字列オブジェクトを作成すると、2 つのオブジェクトが作成されます。 1 つは SCP に、もう 1 つはヒープにあり、参照変数はスタックに保存されます。
を使用してリテラルの「MyString」をすでに作成しました。文字列 str1 = “MyString”;
SCP 内に重複を持たせることはできないため、JVM は SCP 内にもう 1 つのオブジェクトを作成しませんが、スタック内の変数 str3 への既存の参照を返し、ヒープ内に 1 つのオブジェクトを作成します。 Str3 はヒープ内のオブジェクト「MyString」を指しますが、SCP にはありません。
次に、文字列オブジェクトにメモリが割り当てられる方法のさまざまなケースを示します。
ケース 1: 上記で定義された文字列オブジェクトがメモリに格納される方法。
パブリック クラス stringsStorageConcept
{
public static void main(String[] args)
{
文字列 str1 = “MyString”;
文字列 str2 = 新しい文字列(“MyString”);
System.out.println(str1 == str2); //出力:False
System.out.println(str1.equals(str2)); //出力:True
}
}
「==」演算子を使用して str1 と str2 を比較すると、false が返されます。ご存知のとおり、「==」演算子は物理アドレスを比較します。この例では、str1 は SCP 内のオブジェクトを指し、str2 はヒープ内のオブジェクトを指します。したがって、 false を返します。
しかし、str1.equals(str2) の場合、ご存知のとおり、「equals」関数は個々の文字をチェックし、str1 と str3 の両方に同じ値が格納されているため、true が返されます。
ケース 2: 別の文字列リテラル
文字列 str3 = “MyString”;
str1 と str3 はどちらも SCP 内の同じ文字列リテラルを指します。
パブリック クラス stringsStorageConcept
{
public static void main(String[] args)
{
文字列 str1 = “MyString”;
文字列 str3 = “MyString”;
System.out.println(str1 == str2); //出力:True
System.out.println(str1.equals(str2)); //出力:True
}
}
s1 == s3 は、「==」演算子が物理アドレスを比較するが内容は比較しないため、true を返します。
s1.equals(s3) は true を返し、「equals」関数は両方の参照変数の個々の文字をチェックします。
ケース 3: 新しいキーワードを使用して別の文字列オブジェクトが作成されます
文字列 str4 = 新しい文字列(“NewString”);
この場合、JVM は SCP でこの文字列をチェックします。値「NewString」を持つ文字列オブジェクトが見つからないため、2 つのオブジェクトを 1 つは SCP に作成し、もう 1 つはヒープに作成します。参照変数 str4 は次の場所に保存されます。スタック。 Str4 にはヒープ内のオブジェクトへの参照が含まれます。
ケース 4: 別の文字列リテラルが作成されます。
文字列 str5 = “新しい文字列”;
この場合、JVM はこのリテラルがすでに利用可能かどうかを SCP でチェックします。ここでは「NewString」が SCP にすでに存在しているため、JVM は SCP に重複を作成せず、代わりに変数 str5 への参照を返します。
ケース 5: ある文字列を別の文字列に代入する
文字列 str4 = 新しい文字列(“NewString”);
文字列 str6 = str4; //代入
ここで、str6 と str4 はヒープ内の同じオブジェクトを指し、str4 の値は消去されません。
パブリック クラス stringsStorageConcept
{
public static void main(String[] args)
{
文字列 str4 = 新しい文字列(“NewString”);
文字列 str6 = str4;
System.out.println(str4 == str6); //出力: true
}
}
JVM は、ヒープ内の「NewString」の参照を変数 str6 に与えます。これが、str4 == str6 が true を返す理由です。
結論として、文字列リテラルを使用し、「new」演算子によって文字列オブジェクトを作成することには、長所と短所があります。
文字列リテラルを使用すると、重複を作成せずにメモリをより効率的にすることができます。 JVM は 1 つの一意のオブジェクトを作成し、文字列は SCP 内に永久に残ります。この欠点は、文字列プールのサイズが固定されており、いつかいっぱいになることです。
しかし、新しいキーワードを使用すると、2 つのオブジェクトが作成され、1 つは SCP に、もう 1 つはヒープに作成されます。ヒープでは、オブジェクトが必要ない場合、スペースを作るためにガベージ コレクターによって消去されます。しかし、これの欠点は、「new」演算子を使用すると、JVM は常に新しいオブジェクトを作成する必要があり、JVM にとってオーバーロードになることです。
免責事項: 提供されるすべてのリソースの一部はインターネットからのものです。お客様の著作権またはその他の権利および利益の侵害がある場合は、詳細な理由を説明し、著作権または権利および利益の証拠を提出して、電子メール [email protected] に送信してください。 できるだけ早く対応させていただきます。
Copyright© 2022 湘ICP备2022001581号-3