文字列と文字列定数プール

文字列と文字列定数プール

文字列定数プールの設計思想は何ですか?

  1. 文字列の割り当ては、他のオブジェクトの割り当てと同様に、時間とスペースを大量に消費し、最も基本的なデータ型であるため、頻繁かつ大量に作成され、プログラムのパフォーマンスに大きな影響を与えます。
  2. パフォーマンスを向上させ、オーバーヘッドを削減するために、JVM は文字列定数をインスタンス化するときにいくつかの最適化を行い、キャッシュ領域に似た文字列用の文字列定数プールをオープンしました。
    • 文字列定数を作成するとき、首相は文字列定数プールにクエリを実行して、その文字列が存在するかどうかを確認します。
      • Exists: 参照インスタンスを返します。
      • 存在しません: 文字列をインスタンス化してプールに入れます

文字列定数プールとは何ですか?

毎回同じ文字列オブジェクトとメモリ割り当てが作成されることを避けるために、Java は内部最適化を行って文字列リテラルをキャッシュ領域に格納します。このキャッシュ領域は文字列定数プールと呼ばれます

文字列定数プールはどこにありますか?

画像の説明を追加してください

JDK1.7 以降の場合、文字列定数プールはヒープ内にあります。

JDK1.6の場合、文字列定数プールはメソッド領域にあります。

典型的な質問:

String s1 = "aaa";
String s2 = "aaa";
System.out.println(s1 == s2);//true
//因为"aaa"为字面量,在编译时期就会直接在字符串常量池生成,而 s1和s2是引用的 "aaa"在字符串常量池中的引用,所以s1=s2
String s = new String("aaa");//创建了几个对象
//两个,第一个对象"aaa"会存储在字符串常量池中,因为有new 操作,所以还会在堆中创建一个对象,此时s指向的是堆中的字符串对象
String s1 = new String("aaa");
String s2 = new String("aaa");//一共创建了几个对象
System.out.println(s1 == s2);//打印true还是false
//第一个问题,一共创建了几个对象?
//3个,第一个对象因为"aaa"是字面量在编译时期就在字符串常量池中创建出来,在执行new String("aaa")时,首先回去字符串常量池equals比较是否存在"aaa"字符串,此时存在,则不再在字符串常量池中创建对象,但是有new 操作,所以又会在heap堆中创建一个对象。因为new了两次,所以在heap中创建了两个对象,加上字符串常量池中的对象一个是3个对象
//第二个问题,s1==s2是true还是false
//false,因为s1和s2分别指向的是heap中各自对象的地址值,一定是不相等的,所以为false
String s1 = "he";
String s2 = s1+new String("llo");//创建了几个对象
//4个
//在编译时期,字面量"he"和"llo"会先进字符串常量池,进行了一次new String("llo") 操作,此时会在heap中创建一个对象,运行到 "he"+new String("llo")时,还会进行拼接操作,此时还会在heap堆中再创建一个对象,所以一个会创建4对象
//下面代码创建了几个对象?
String s1 = new String("he") + new String("llo");
String s2 = s1.intern();  

	//对于jdk1.7来说,创建了5个对象,“he” "llo"字面量会先去常量池中查看是否存在,不存在,则会在常量池中创建这两个对象,然后他们都进行了new String()操作,所以还会在堆中非常量池区域再各自创建一个对象,最后 把new 出来的对象拼接起来,此时还会在堆中非常量区创建一个对象,所以一共是5个对象。
	//对于jdk1.6来说,s1和jdk1.7一样,会创建5个对象
	//s1.intern();对于jdk1.7来说,会先去字符串常量池进行eq,如果不存在相同的字符串,则会直接指向堆中s1的实例,也就是说s1.intern()返回的是s1堆中对象的指针,此时s2和s1指向的都是同一个对象,所以s1==s2 为true
	//对于jdk1.6来说,intern()操作会先去常量池进行eq,发现不存在,会在常量池创建一个“hello”对象,然后把这个“hello”返回给s2,所以对于jdk1.6来说,s1==s2 为 false
//这行代码会创建对象吗
String s1 = "java";
//不一定,因为"java"字符串大概率会在jdk源码中被先创建出来,此时s1直接会指向字符串常量池中的"java"的地址值

文字列を繋ぐ際の「+」記号の使用について

String s1 = "he"+"llo";
//在编译时期,对于确定的常量类型,编译器进行优化,直接编译成String s1 = "hello",所以在运行时不会再发生拼接操作,直接会在字符串常量池创建一个对象
String s1 = "he";
String s2 = s1+"llo";
//对于编译器老说,在执行s2 = s1+"llo"时,编译器实际上会创建一个StringBuilder对象进行append进行拼接,然后再进行toString()方法返回,通过查看toString()方法的源码发现,实际上是进行了一次new String()操作,所以还会在deap堆中创建一个拼接后的对象,所以一共会创建3个对象

新しい StringBuilder().toString() ソース コード

String オブジェクトは不変オブジェクトについて

String オブジェクトが不変オブジェクトであるという事実は、String のスプライシング メソッドを通じて確認できます。これは、すべての String オブジェクトが StringBuilder オブジェクトを使用して内部的にスプライスされ、StringBuilder オブジェクトの内部ソース コードが最終的に新しい String() 操作を実行するためです。

Javaにおける文字列のような定数技術の応用

Integer s1 = -128;
Integer s2 = -128;
System.out.println(s1 == s2);//true
Integer s3 = -129;
Integer s4 = -129;
System.out.println(s3 == s4);//false

整数 -128 と 127 の間で定数が使用され、等価比較を直接実行できることは誰もが知っていますが、なぜでしょうか?
実際、実行中に、Integer s1 = -128; は Integer s1 = Integer.valueOf(-128) にコンパイルされます。ソース コードを見ると、Integer は内部初期化中に最初にオブジェクト プールを初期化することがわかります。このオブジェクト プールのスコープは -128 から 127 です。valueOf() 操作を実行するとき、最初にオブジェクト プールに行ってそれを見つけます。見つかった場合は直接返されます。見つからなかった場合は、したがって、-128 から 127 までの値が直接 == 比較の場合、同じオブジェクトと比較される場合は true が返され、範囲外で比較される場合は、異なるオブジェクトと比較されるため、虚偽であること。

整数は静的内部クラスを通じて初期化されます

画像の説明を追加してください

valueOf のソース コード
画像の説明を追加してください
注: Byte、Short、Integer、Long、および Character はすべて、同様のオブジェクト プール テクノロジを使用します。

おすすめ

転載: blog.csdn.net/XX777666/article/details/120560147
おすすめ