ホームページ Java &#&チュートリアル Java の intern() メソッドの詳細な分析

Java の intern() メソッドの詳細な分析

May 19, 2017 am 09:47 AM
java

1. 文字列の問題

文字列は実際、日常のコーディング作業に非常に役立ち、比較的簡単に使用できるため、特に詳しく研究した人はほとんどいません。一方、面接や筆記試験では、より踏み込んだ難しい質問が行われることがよくあります。採用の際、私は候補者に関連する質問をすることがありますが、これは特に正確で詳細な質問をする必要があるという意味ではありません。1 つは基本的な知識の理解をテストすることです。 2 つ目は、JAVA の基礎知識をテストすることです。2 つ目は、技術に対する受験者の態度をテストすることです。

次のプログラムが何を出力するか見てみましょう?すべての質問に正しく答えられ、その理由がわかれば、この記事はあなたにとってあまり意味がありません。答えが間違っている場合、または原理があまり明確でない場合は、この記事を詳しく見て、各プログラムの結果とその結果が出力される根深い理由を明確に理解するのに役立ちます。

コード セグメント 1:

package com.paddx.test.string;
public class StringTest {
    public static void main(String[] args) {
        String str1 = "string";
        String str2 = new String("string");
        String str3 = str2.intern();
 
        System.out.println(str1==str2);//#1
        System.out.println(str1==str3);//#2
    }
}
ログイン後にコピー

コード セグメント 2:

package com.paddx.test.string;
public class StringTest01 {
    public static void main(String[] args) {
        String baseStr = "baseStr";
        final String baseFinalStr = "baseStr";
 
        String str1 = "baseStr01";
        String str2 = "baseStr"+"01";
        String str3 = baseStr + "01";
        String str4 = baseFinalStr+"01";
        String str5 = new String("baseStr01").intern();
 
        System.out.println(str1 == str2);//#3
        System.out.println(str1 == str3);//#4
        System.out.println(str1 == str4);//#5
        System.out.println(str1 == str5);//#6
    }
}
ログイン後にコピー

コード セグメント 3 (1):

package com.paddx.test.string;  
public class InternTest {
    public static void main(String[] args) {
 
        String str2 = new String("str")+new String("01");
        str2.intern();
        String str1 = "str01";
        System.out.println(str2==str1);//#7
    }
}
ログイン後にコピー

コード セグメント 3 (2):

package com.paddx.test.string;
 
public class InternTest01 {
    public static void main(String[] args) {
        String str1 = "str01";
        String str2 = new String("str")+new String("01");
        str2.intern();
        System.out.println(str2 == str1);//#8
    }
}
ログイン後にコピー

説明の便宜上、上記のコードの私の出力を示します。 #1 ~#8 によるコード化が行われ、以下の青字部分が結果となります。

2. 文字列の詳細な分析

1. コードセグメント1の分析

文字列は基本型に属しませんが、基本型と同様にリテラルを介して直接割り当てることもできます。新しいオブジェクトを通じて文字列を生成します。ただし、リテラル代入による文字列の生成と new の間には本質的な違いがあります。

Java の intern() メソッドの詳細な分析

リテラル代入によって文字列を作成する場合、同じ文字列が 定数プールにすでに存在するかどうかが最初に検索されます。すでに存在する場合は、スタック内の reference は文字列を直接指します。存在しない場合は、定数プール内に文字列が生成され、スタック内の参照がその文字列を指します。 new を通じて文字列を作成すると、文字列オブジェクトがヒープに直接生成されます (JDK 7 以降、HotSpot は定数プールを永続世代からヒープに転送しました。詳細については、「JDK8 メモリ モデル 」を参照してください) - 消えた PermGen」の記事)、スタック内の参照はオブジェクトを指しています。ヒープ内の文字列オブジェクトの場合、 intern() メソッドを通じて文字列を定数プールに追加し、定数への参照を返すことができます。

これで、コード セグメント 1 の結果を明確に理解できるはずです。

結果 #1: str1 は文字列内の定数を指し、str2 はヒープ内に生成されたオブジェクトであるため、str1==str2 は false を返します。

結果 #2: str2 は intern メソッドを呼び出し、str2 の値 (「string」) を定数プールにコピーしますが、その文字列は定数プール (つまり、str1 が指す文字列) にすでに存在します。したがって、文字は直接 String 参照として返されるため、str1==str2 は true を返します。

以下はコード セグメント 1 の実行結果です:

Java の intern() メソッドの詳細な分析

2. コード セグメント 2 の分析

コード セグメント 2 の結果については、StringTest01.class ファイルを逆コンパイルすると理解しやすくなります。

定数プールの内容(部分):

Java の intern() メソッドの詳細な分析

実行命令(部分、2列目の#+ordinalが定数プールの項目に対応):

Java の intern() メソッドの詳細な分析

上記の実行処理を説明する前に、まず、 2 つの命令:

ldc : 実行時定数プールから項目をプッシュし、指定された項目の参照を定数プールからスタックにロードします。

astore_: 参照をローカル変数に保存し、その参照を n 番目のローカル

変数 に割り当てます。

ここで、コードセグメント 2 の実行プロセスの説明を開始します:

0: ldc #2: 定数プールの 2 番目の項目 (「baseStr」) をスタックにロードします。

2: astore_1 : 1 の参照を最初のローカル変数、つまり StringbaseStr = "baseStr" に割り当てます

3: ldc #2: 定数プールの 2 番目の項目 ("baseStr") を真ん中をスタックします。

5: astore_2 : 3 の参照を 2 番目のローカル変数、つまり、final String に代入します。

6: ldc #3: 定数プールの 3 番目の項目 ("baseStr01") をロードします。スタック内にあります。

8: astore_3: 6 の参照を 3 番目のローカル変数、つまり String str1="baseStr01";

に割り当てます。

9: ldc #3: 定数プールの 3 番目の項目 (「baseStr01」) をスタックにロードします。

11: astore 4: 9 の参照を 4 番目のローカル変数に割り当てます: String str2="baseStr01";

結果 #3: str1 と str2 は両方とも定数を指しているため、str1==str2 は確実に true を返します。プール内の参照アドレス。実際、JAVA 1.6 以降では、コンパイル段階で定数文字列の「+」演算が文字列に直接合成されます。

13: 新しい #4: StringBuilder のインスタンスを生成します。

16: dup: 13で生成されたオブジェクトの参照をコピーし、スタックにプッシュします。

17: invokespecial #5: 定数プールの 5 番目の項目である StringBuilder. メソッドを呼び出します。

上記の 3 つの命令は、StringBuilder オブジェクトを生成するために使用されます。

20: aload_1 : 最初のパラメータの値「baseStr」をロードします

21: invokevirtual #6: StringBuilder オブジェクトの append メソッドを呼び出します。

24: ldc #7: 定数プールの 7 番目の項目 (「01」) をスタックにロードします。

26: invokevirtual #6: StringBuilder.append メソッドを呼び出します。

29: invokevirtual #8: StringBuilder.toString メソッドを呼び出します。

32: astore 5: 29の結果参照の代入を5番目のローカル変数、つまり変数str3への代入に変更します。

結果 #4: str3 は実際には stringBuilder.append() によって生成された結果であるため、str1 と等しくなく、結果は false を返します。

34: ldc #3: 定数プールの 3 番目の項目 (「baseStr01」) をスタックにロードします。

36: astore 6: 34 の参照を 6 番目のローカル変数、つまり str4="baseStr01" に割り当てます。

結果 #5: str1 と str4 は両方とも定数プール内の 3 番目の項目を指しているため、str1 ==str4 は true を返します。ここでは、final フィールドの場合はコンパイル時に定数の置換が直接実行されるのに対し、non-final フィールドの場合は実行時に代入処理が実行されるという現象も見られます。 38: 新しい #9: String オブジェクトを作成します

41: DUP: 参照をコピーし、スタックと同様に押します。

42: ldc #3: 定数プールの 3 番目の項目 (「baseStr01」) をスタックにロードします。

44: invokespecial #10: String."" メソッドを呼び出し、ステップ 42 で参照をパラメータとしてメソッドに渡します。

47: invokevirtual #11: String.intern メソッドを呼び出します。

38から41に対応するソースコードはnew String(“baseStr01″).intern()です。

50: astore 7: ステップ 47 で返された結果を変数 7 に代入します。つまり、str5 は定数プール内のbaseStr01 の位置を指します。

結果 #6: str5 と str1 は両方とも定数プール内の同じ文字列を指しているため、str1==str5 は true を返します。

コード セグメント 2 を実行すると、出力結果は次のようになります:

Java の intern() メソッドの詳細な分析

3. コード セグメント 3 の分析:

コード セグメント 3 の実行結果は、JDK 1.6 と JDK 1.7 で異なります。まず実行結果を見て、その理由を説明しましょう:

JDK 1.6 での実行結果:

Java の intern() メソッドの詳細な分析 JDK 1.7 での実行結果:

Java の intern() メソッドの詳細な分析 コードセグメント 1 の分析によると、単純に JDK 1.6 の結果を取得する必要があります。str2 と str1 は元々異なる場所を指しているため、false を返す必要があります。

奇妙な問題は、JDK 1.7 以降、最初のケースでは true が返されるが、位置を変更すると返される結果が false になることです。この主な理由は、JDK 1.7 以降、HotSpot が定数プールを永続世代からメタスペースに移動したため、JDK 1.7 以降のインターン メソッドは実装において比較的大きな変更を受けています。まだ使用されている場合は、定数プールに既に存在するかどうかを確認します。存在する場合は、対応する文字列が見つからない場合と異なります。定数プールの場合、文字列は定数プールにコピーされ、元の文字列への参照のみが定数プール内に生成されます。つまり:

結果 #7: 最初のケースでは、定数プールに文字列 "str01" が存在しないため、ヒープ内の "str01" への参照が定数プールに生成され、リテラル代入を実行するときに、定数プールにはすでに存在しているため、参照を直接返すだけです。したがって、str1 と str2 は両方ともヒープ内の文字列を指し、true を返します。

結果 #8: 位置を交換した後、リテラル代入 (String str1 = "str01") を実行するときに定数プールが存在しないため、str1 は定数プール内の位置を指し、str2 は定数プール内の位置を指します。 heap オブジェクトの場合、intern メソッドが実行されると、str1 と str2 には影響しないため、false が返されます。

【関連おすすめ】

1. Javaの無料ビデオチュートリアル

2. JAVAのintern()メソッドの使用体験まとめ

3. Javaのinternメソッドの概念とは

4 . Javaのintern()の関数の解析

5. Stringオブジェクトのintern()の詳細説明

以上がJava の intern() メソッドの詳細な分析の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。

ホットAIツール

Undresser.AI Undress

Undresser.AI Undress

リアルなヌード写真を作成する AI 搭載アプリ

AI Clothes Remover

AI Clothes Remover

写真から衣服を削除するオンライン AI ツール。

Undress AI Tool

Undress AI Tool

脱衣画像を無料で

Clothoff.io

Clothoff.io

AI衣類リムーバー

AI Hentai Generator

AI Hentai Generator

AIヘンタイを無料で生成します。

ホットツール

メモ帳++7.3.1

メモ帳++7.3.1

使いやすく無料のコードエディター

SublimeText3 中国語版

SublimeText3 中国語版

中国語版、とても使いやすい

ゼンドスタジオ 13.0.1

ゼンドスタジオ 13.0.1

強力な PHP 統合開発環境

ドリームウィーバー CS6

ドリームウィーバー CS6

ビジュアル Web 開発ツール

SublimeText3 Mac版

SublimeText3 Mac版

神レベルのコード編集ソフト(SublimeText3)

Javaの完全数 Javaの完全数 Aug 30, 2024 pm 04:28 PM

Java における完全数のガイド。ここでは、定義、Java で完全数を確認する方法、コード実装の例について説明します。

ジャワのウェカ ジャワのウェカ Aug 30, 2024 pm 04:28 PM

Java の Weka へのガイド。ここでは、weka java の概要、使い方、プラットフォームの種類、利点について例を交えて説明します。

Javaのスミス番号 Javaのスミス番号 Aug 30, 2024 pm 04:28 PM

Java のスミス番号のガイド。ここでは定義、Java でスミス番号を確認する方法について説明します。コード実装の例。

Java Springのインタビューの質問 Java Springのインタビューの質問 Aug 30, 2024 pm 04:29 PM

この記事では、Java Spring の面接で最もよく聞かれる質問とその詳細な回答をまとめました。面接を突破できるように。

Java 8 Stream Foreachから休憩または戻ってきますか? Java 8 Stream Foreachから休憩または戻ってきますか? Feb 07, 2025 pm 12:09 PM

Java 8は、Stream APIを導入し、データ収集を処理する強力で表現力のある方法を提供します。ただし、ストリームを使用する際の一般的な質問は次のとおりです。 従来のループにより、早期の中断やリターンが可能になりますが、StreamのForeachメソッドはこの方法を直接サポートしていません。この記事では、理由を説明し、ストリーム処理システムに早期終了を実装するための代替方法を調査します。 さらに読み取り:JavaストリームAPIの改善 ストリームを理解してください Foreachメソッドは、ストリーム内の各要素で1つの操作を実行する端末操作です。その設計意図はです

Java での日付までのタイムスタンプ Java での日付までのタイムスタンプ Aug 30, 2024 pm 04:28 PM

Java での日付までのタイムスタンプに関するガイド。ここでは、Java でタイムスタンプを日付に変換する方法とその概要について、例とともに説明します。

カプセルの量を見つけるためのJavaプログラム カプセルの量を見つけるためのJavaプログラム Feb 07, 2025 am 11:37 AM

カプセルは3次元の幾何学的図形で、両端にシリンダーと半球で構成されています。カプセルの体積は、シリンダーの体積と両端に半球の体積を追加することで計算できます。このチュートリアルでは、さまざまな方法を使用して、Javaの特定のカプセルの体積を計算する方法について説明します。 カプセルボリュームフォーミュラ カプセルボリュームの式は次のとおりです。 カプセル体積=円筒形の体積2つの半球体積 で、 R:半球の半径。 H:シリンダーの高さ(半球を除く)。 例1 入力 RADIUS = 5ユニット 高さ= 10単位 出力 ボリューム= 1570.8立方ユニット 説明する 式を使用してボリュームを計算します。 ボリューム=π×R2×H(4

Spring Tool Suiteで最初のSpring Bootアプリケーションを実行するにはどうすればよいですか? Spring Tool Suiteで最初のSpring Bootアプリケーションを実行するにはどうすればよいですか? Feb 07, 2025 pm 12:11 PM

Spring Bootは、Java開発に革命をもたらす堅牢でスケーラブルな、生産対応のJavaアプリケーションの作成を簡素化します。 スプリングエコシステムに固有の「構成に関する慣習」アプローチは、手動のセットアップを最小化します。

See all articles