あなたが知らない秘密--String s=new String(「abc」)はいったいいくつのオブジェクトを作成したのですか?

9010 ワード

String s=new String(「abc」)はいくつのオブジェクトを作成しますか?
上記の問題の結論を検討する前に,定数プールという概念を理解する必要がある.
定数プール
  文字列がJavaで大量に使用されるため、毎回同じ文字列オブジェクトが作成されるのを避けるために(これはより多くのメモリを占めることを意味する)、JVMは文字列オブジェクトに対して一定の最適化を行い、文字列定数を格納する専門の領域があり、この領域が文字列定数プールである.定数プール(constant pool)とはコンパイル期間中に決定されることを意味する.コンパイル済みに保存する.classファイルの一部のデータ.クラス、メソッド、インタフェースなどの定数、文字列定数も含まれます.
  注意しなければならないのは:
  • はJDK 1にある.6従来、定数プールはJVMのメソッド領域に存在していた.
  • JDK 7以降、定数プールはスタック内に置かれる.公式サイトの説明:
    Synopsis: In JDK 7, interned strings are no longer allocated in the permanent generation of the Java heap, but are instead allocated in the main part of the Java heap (known as the young and old generations), along with the other objects created by the application. This change will result in more data residing in the main Java heap, and less data in the permanent generation, and thus may require heap sizes to be adjusted. Most applications will see only relatively small differences in heap usage due to this change, but larger applications that load many classes or make heavy use of the String.intern() method will see more significant differences.

  • 文字列定数プールの概念を理解した後、コードを見てみましょう.
    public class StringDemo {
    	public static void main(String[] args) {
    		String str1 = "abc";
    		String str2 = "abc";
    		String str3 = new String("abc");
            
    		System.out.println(str1==str2); //   
    		System.out.println(str2==str3);//   
    	}
    }
    

    上記のコードを見て、コンソールの出力を予測してください.
      7行目出力true,8行目falseを出力する.
    プロセスの実行:
  • はString str 1=「abc」を実行する. ,JVM "abc" , , str1`.
  • String str2 = "abc";を実行すると、JVMは定数プールで"abc"という文字列を見つけたので、直接アプリケーションを添付します.
  • String str3 = new String("abc");を実行すると、JVMはスタックにStringオブジェクトを作成し、転送された定数プールStringオブジェクトに保存されているchar[]配列をスタックのStringに割り当てます.
    /**
    	String       
    **/
    /** The value is used for character storage. */
    private final char value[]; 
    
    /** Cache the hash code for the string */
    private int hash; // Default to 0
    
    public String(String original) {//String    
            this.value = original.value;
            this.hash = original.hash;
     }
    

  • 最初の質問に戻ると、String s=new String(“abc”)はいったいいくつのオブジェクトを作成しましたか?
      String s=new String(“abc”)という文を実行する前に定数プールに"abc"が存在しなかった場合、new String()の作成時に定数プールに文字列定数を作成し、この文字列定数によってスタックに新しい文字列を作成します.しかし、この2つの文字列オブジェクト(定数プールの「abc」とスタックの「abc」)の最下位に保存されている文字の配列はいずれも1つです.
      実行前に"abc"という文字列定数(例えば上のコード)が存在していた場合、String s=new String(“abc”)という文を実行すると、スタックに1つのオブジェクトしか作成されません.
    定数プールのabcとスタックのabcの最下位の保存文字の配列が1つであることを確認します.
    Stringのコンストラクタを確認した後、newキーワードを使用してスタックに作成された"abc"と定数プールの"abc"は、オブジェクトは1つではありませんが、2つのオブジェクトの下部が指す配列が1つであると結論しました.コードによってこの結論を検証します.
    全体的な考え方は、定数語の文字列オブジェクトの下位配列の値を反射することによって修正し、スタックのStringオブジェクトの値が変化するかどうかを見ます.
    @Test
    public void test() throws Exception {
    	//         "abc"
    	String str = "abc";
    	//       "abc"       String  
    	String str2 = new String("abc");
    	
    	//  String   value  
    	Field field = String.class.getDeclaredField("value");
    	//          
    	field.setAccessible(true);
    	
    	//  str    value    
    	char[] arr = (char[]) field.get(str);
    	arr[2]='1';
            
    	System.out.println(str);//  :ab1
    	System.out.println(str2);//  :ab1
    }