アルゴリズムコンペティションエントリークラシック(Liu Rujia)フルバージョン

アルゴリズムコンペティションエントリークラシック(Liu Rujia)フルバージョンpdf
クラシックホワイトブック、誰もACMerを知らない、右

ファイル:n459.com/file/25127180-479205949

以下は関係ありません。

- - - - - - - - - - - - - - - - - - - - - -境界線 - - - ----------------------------------------

ここに画像の説明を挿入します。
通常、結果は「==アドレスを比較し、等しい値を比較する」という定理に従って取得できます。ただし、Stringは少し特殊です。newString(string)によって生成された同じ値の2つの文字列のアドレスは等しくなく、他のメソッドによって生成された同じ値の2つの文字列のアドレスは等しくなります。

コードは次のように表示されます。

// 第一种方式创建字符串,字面量赋值
String str1 = "abc";
String str2 = "abc";
// 第二种方式创建字符串
String str3 = new String("xyz");
String str4 = new String("xyz");
System.out.println(str1 == str2); //true
System.out.println(str3 == str4); //false

同じことが文字列を作成することです。これは、定数プールとヒープを含む、同等の文字列の2つのペアの結果が異なる理由です。

最初の方法で作成された文字列は、リテラル「abc」を定数プールに配置し、str1とstr2の両方が定数プールの「abc」を指すため、2つの変数のアドレスは同じです。2番目の方法が作成されます。文字列、最初に定数プールに「xyz」を配置し、次に定数プールの「xyz」をコンストラクターを介してヒープにコピーして、定数プールの「xyx」とは関係のない新しい文字列を生成します。 、したがって、2つの変数はヒープ内の2つの異なる変数を指しているため、2つの変数のアドレスは異なります。

intern()とは何ですか?定数プールとの関係は何ですか?

定数プール
定数プールは、リテラル、シンボリック参照、または直接参照を格納する場所です。定数プールは、クラス定数プールとランタイム定数プールに分けられます。

クラス定数プール
クラス定数プールは、コンパイル中にクラスにリテラルおよびシンボリック参照を格納するためのものです。上記の文字列「abc」はリテラルです。シンボル参照は、クラスとインターフェイスの完全修飾名、フィールドの名前と記述子、およびメソッドの名前と記述子です。

図に示すように
symbolrefnum
。この図には、シンボル参照である定数プール内の新しいString(String)メソッドの名前と記述子があります。

ランタイム
定数プール私たちが通常言う定数プールは、ランタイム定数プールを指します。クラス読み込みの解析フェーズでは、クラス定数プールがメモリに読み込まれ(JDK1.7がメソッド領域に配置される前、現在はヒープ内にあります)、シンボル参照は直接参照に解決されます。つまり、メソッド/クラスの説明情報を指します。メモリ内の対応するメソッド/クラス。実行時定数プールは動的であり、実行時に新しい変数を定数プールに追加できます。

intern()は、
最初にintern()メソッドの説明を確認します。interndescription
は、第2レベルの英語レベルのウェーブを変換し、文字列がintern()を呼び出すときに、プール内の文字列値に等しい文字列オブジェクトがある場合に影響を与えます。 、文字列プール内の文字列オブジェクトが返されます。そうでない場合は、文字列が追加され、この文字列への参照が返されます。文字列プールは、Stringクラスによってプライベートに維持されます。

ここでも、文字列プールの概念が紹介されています。

文字列プール
文字列プールは、文字列オブジェクトではなく、定数プール内の文字列オブジェクトへの参照を格納します。最初のリテラル割り当てメソッドで作成された文字列は定数プールに配置され、文字列プールは文字列オブジェクトへの参照を格納します。文字列が定数プールで再度作成されると、文字列プールが最初にチェックされます。この文字列への同等の参照があり、存在する場合は、この参照に対応するオブジェクトを直接指します。

2番目の方法では、2番目の方法で作成された文字列は、構築パラメーターと同じ値の文字列がある場合に文字列プールで検索して、定数プールに新しい文字列を作成する必要があるかどうかを判断し、定数プールに文字列をコピーしてヒープに作成します。新しい文字列。
ここに画像の説明を挿入します。
図に示すように、オリジナルという名前の新しい文字列がヒープ内の定数プールに作成され、新しい文字列がコピーされてヒープ内に生成されます。コメントでは、文字列の明示的なコピーが必要でない限り、文字列は不変であるため、このコンストラクターを使用する必要はないとも述べています。

ここでは、intern()を使用して文字列プールをテストします。

public static void main(String[] args) {
	  //第一部分 测试
    String str1 = "abc";
    String str2 = new String("abc");
    System.out.println(str1.intern() == str1); //true
    System.out.println(str1.intern() == str2); //false
    System.out.println(str1.intern() == str2.intern()); //true
    //第二部分 测试通过char[]创建字符串后,引用是否会进入字符串池
    String str3 = new String(new char[]{'g', 'h'});
    String str4 = "gh";
    System.out.println(str3.intern() == str3); //false
    System.out.println(str3.intern() == str4); //true
    //第三部分 测试char[]创建的字符串调用intern()后引用是否进入字符串池
    String str3 = new String(new char[]{'g', 'h'});
    str3.intern();
    String str4 = "gh";
    System.out.println(str3.intern() == str3); //true
    System.out.println(str3.intern() == str4); //true
}

コードの上記の3つの部分は、独立したテストです。

最初の部分:str1は定数プールにabcを作成し、参照を文字列プールに配置します。str2は定数プールにabcをコピーし、ヒープに新しい文字列を作成します。intern()が文字列プールから取得するのは、定数プール内のstr1のabc参照です。

2番目の部分:str3は、定数プールではなく、char []を介してヒープ内に文字列を作成するため、gh参照は文字列プールに自動的に配置されません。str4は定数プールにghを作成するため、str4のgh参照は文字列プールに保存されます。intern()が文字列プールから取得するのは、定数プール内のstr4のgh参照です。

3番目の部分:str3は、定数プールではなく、char []を介してヒープ内に文字列を作成するため、ghの参照は自動的に文字列プールに入れられませんが、intern()を呼び出して、str3の参照をghに手動で追加します。プール内の文字列。リテラル割り当てを使用してstr4が作成されると、クエリは文字列プールにghへの参照があることを検出し、str4はstr3のgh参照を指します。intern()が文字列プールから取得するのは、ヒープ内のstr3のgh参照です。

上記のコードからも結論付けられます:intern()はヒープに作成された文字列参照を置くことができ、文字列プールには文字列プールへの同等の参照がありません。

同時に、これは文字列が不変である理由を説明することもできます。
これにより、複数の参照が文字列プール内の同じオブジェクトを同時に指すことができるようになります。文字列が変更可能である場合、参照操作の1つがオブジェクトの値を変更します。これは他の参照に影響しますが、これは明らかに不可能です。

Zhihu
の主題に戻ります。定数プールに「string」を作成し、その参照を文字列プールに入れます。str1はintern()を呼び出して定数プールの参照を返し、str1はヒープ内の参照を指しているため、出力はfalseです。

StringBuilderのtoString()は、char []を介して文字列を作成します
ここに画像の説明を挿入します
。ヒープにabcdefを作成した後、str2はintern()を呼び出して、ヒープ内の参照を文字列プールに入れ、str2を指すこの参照を返します。ヒープ内の同じ文字列オブジェクトなので、出力はtrueです。

結論
Javaの小さな問題が、最下層の理論的研究であろうとJVMの理論的研究であろうと、多くの知識ポイントを放射することがあり、アプリケーションケースと組み合わせるとより深い理解が得られます。記事で述べたように、定数プールはクラスファイル構造とクラスローディング理論の研究の一部です。

おすすめ

転載: blog.csdn.net/gumenghua_com1/article/details/112652521