Javaの文字列を破壊!


この文章は優雅な科学技術評論ページと一緒に発表された.

文字と文字列


Javaプログラムの実行中に最も作成されるオブジェクトは何か知っていますか?文字列オブジェクトです.
文字列は文字の配列です.「abc」文字列は、「a」、「b」、および「c」の文字が配列された配列である.
Javaはオブジェクト向けのプログラミングであり,他の非内蔵Primitive Typeはオブジェクトからなる.
Javaでは、Primitiveタイプの値はbyte、short、int、long、float、double、char、boolean、voidです.
では、文字列は他のオブジェクトと同じですか?
そうじゃない!String name = "lxxjn0"String name = new String("lxxjn0")の違いを理解し、一つ一つ確認してみましょう.

Javaの文字列


文字列、new、literal(literal)の作成方法


通常、オブジェクトの作成時にnewキーを使用してオブジェクトを作成します.
しかし、不思議なことに、文字列はnew演算子ではなく値を直接指定することができ、文字列文字(literal)と呼ばれています.
public void string() {
    String name = "lxxjn0"; // 문자열 리터럴 생성
    String name1 = new String("lxxjn0"); // new 연산자를 이용한 문자열 생성
}
表面的には文法的な違いもありますが、実際のメモリに割り当てられた領域にも違いがあります.
1つ目のメソッドnew演算子を使用して文字列オブジェクトを作成すると、メモリのheap領域に通常のオブジェクトのように割り当てられます.2つ目のメソッドliteralを使用すると、String Constant Poolという領域に割り当てられます.
参考までにString Constant Poolの位置はJava 7からHeapエリアに移行しています.
Java 7以前のバージョンではPerm領域に存在していた.Perm領域は主にメタデータの格納に用いられ,GCオブジェクト以外の領域である.
しかし、Java 8の加入に伴いPerm領域は削除され、String Constant PoolはHeapの領域に移動される.
Heap領域はGCのターゲットであるため、String Constant Poolで参照を失った文字列オブジェクトはメモリを返します.

ここでnew演算子とテキストを使用してオブジェクトをもう一度作成します.
メモリ内のステータスをよりよく確認するために、文字文字列とnew演算子文字を集合して宣言します.
public void string() {
    String name = "lxxjn0";
    String name1 = "lxxjn0";
    String name2 = new String("lxxjn0");
    String name3 = new String("lxxjn0");
}
このコードを実行すると、文字列を格納するメモリは次のようになります.

文字列文字を使用して作成されたオブジェクトnamename1は、String Constant Pool内の同じオブジェクトを表示します.
ただし、new演算子を使用して文字列を生成するname2およびname3は、heapで異なるオブジェクトを作成および表示します.
次に、文字列文字とnew演算子を参照資料として使用するときにコンパイルされるクラスコードを示します.
public void testString() throws Exception {
    String abc = "abc";
}

public void testNewString() throws Exception {
    String newAbc = new String("abc");
}
 public void testString() throws java.lang.Exception;
    Code:
       0: ldc           #89                 // String abc
       2: astore_1
       3: return

  public void testNewString() throws java.lang.Exception;
    Code:
       0: new           #33                 // class java/lang/String
       3: dup
       4: ldc           #89                 // String abc
       6: invokespecial #93   // Method java/lang/String."<init>":(Ljava/lang/String;)V
       9: astore_1
      10: return

文字列の比較方法、equalsおよびピア比較演算子


では、文字列を比較する際にどのように比較しますか?
主にequals()メソッドまたは同等比較演算子==が使用される.
上記のコード比較値に基づいてどのような結果が得られますか?


直接コードを実行すると、equals()メソッドはtrueを返し、==はfalseを返し、テストに合格できません.
Java Stringのequals()メソッドコードを次のように表示します.

オブジェクトが実際に同じコロン値を持つ場合、または文字列内の値(文字)が同じ場合、trueが返されます.
したがって、new演算子で生成された文字列とliteralで生成された文字列の内部値は同じであり、equals()はtrueを返し、実際のアドレスの==と比較してfalseを返す.
同等比較演算子==は、実際のオブジェクトが持つ浮動小数点値を比較する演算子である.もちろん、Primitive Typeはオブジェクトではないため、比較値と同じです.
再び本題に戻り、最後にnew演算子で生成された文字列とliteralで生成された文字列が異なるアドレスを持つことをテストコードで確認します.
では、文学のあり方はどのように実現されているのでしょうか.

文字列テキストについて


文字列文字については、Stringのintern()メソッドを内部呼び出しているそうです.

String Constant Poolに生成する文字列がすでに存在する場合、intern()メソッドはプライマリ値を返します.存在しない場合、新しいオブジェクトの作成後にプライマリ値を返します.intern()メソッドを使用して、次のようにコードをテストします.

既存のnew演算子によって生成された文字列name1に対してintern()メソッドを実行すると、文字列がname1の値とString Constant Poolにあるかどうかがチェックされます.
String Constant Poolには、nameによって生成されたオブジェクトが既に存在する可能性があるため、nameに示されているアドレスと同じ主切り上げはinternNameに割り当てられる.
したがって、テストは、同じ湧出値を有する文字列であるため、テストに合格することができる.

文字列は可変ではありません!


文字列文字は定数として不変です.これらのプロパティのため、参照する文字列が同じ場合は、同じオブジェクトを参照できます.
Javaソースファイル(.java)がクラスファイル(.class)にコンパイルされてJava仮想マシンにアップロードされると、JVMはString Constant Poolに同じ文字列があるかどうかをチェックし、すでに存在する場合は再使用し、存在しない場合は新しい文字列を作成します.
したがって、複数のパラメータが同じ文字列変数を参照しても、影響を受けず、文字列変数は変わらないため、thread-safeは安全である.
Stringを使用して追加の演算を行う場合、文字列の変更によって既存のオブジェクトは変更されないため、新しいオブジェクトを作成して参照する必要があります.
これは、既存の文字列の参照が消え、ゴミ収集器(Garbage Collector)の収集ターゲットになることを意味します.
JavaのStringは文字列演算でStringBuilderを使用してパフォーマンスを最適化します.
StringBuilderの詳細については、DundonのStringクラスの使用に注意を参照してください.

整理する


Java文字列は、生成方法によってパフォーマンスの違いが生じる可能性があることに注意してください.
Javaで最もよく使われるオブジェクトなので、内部の動作を理解して使用すると、より良いコードを書くのに役立ちます.
だから結論は文字列文字を使って、できるだけnew演算子で生成することを避けます!

コメントリンク


JavaのStringオブジェクトとString Literal-MadPlay's MadLife
[Java]String="vs new String(")の違い-Namjun Kim