Java定数プールの詳細なグラフィックとテキストの説明
Java 定数プールは永遠のトピックであり、面接官のお気に入りです。さまざまな質問があります。Xiaocai は定数プールについてすでに聞いているので、今回はそれをうまくまとめます。
推奨: java ビデオ チュートリアル
jvm 仮想メモリの配布:
プログラム カウンターは、 jvm でプログラムを実行する パイプラインにはいくつかのジャンプ命令が格納されていますが、これは高度すぎて Xiao Cai には理解できません。
ローカル メソッド スタックは、jvm がオペレーティング システムのメソッドを呼び出すために使用するスタックです。
仮想マシン スタックは、Java コードを実行するために jvm によって使用されるスタックです。
メソッド領域には、いくつかの定数、静的変数、クラス情報などが格納されます。これは、メモリ内のクラス ファイルの格納場所として理解できます。
仮想マシン ヒープは、Java コードを実行するために jvm によって使用されるヒープです。
Java の定数プールは、実際には、静的定数プールと実行時定数プールの 2 つの形式に分かれています。
いわゆる静的定数プールは、*.class ファイル内の定数プールです。クラス ファイル内の定数プールには、文字列 (数値) リテラルだけでなく、クラスとメソッドの情報も含まれており、絶対に占有されます。クラスファイルの一部ではなく、スペースの大部分。
ランタイム定数プールとは、jvm 仮想マシンがクラスのロード操作を完了した後、クラス ファイル内の定数プールをメモリにロードし、メソッド領域に保存することを意味します。これを定数プールと呼ぶことがよくあります。 . は、メソッド領域のランタイム定数プールを指します。
次に、インターネット上でよく知られている定数プールの例をいくつか引用して説明します。
String s1 = "Hello"; String s2 = "Hello"; String s3 = "Hel" + "lo"; String s4 = "Hel" + new String("lo"); String s5 = new String("Hello"); String s6 = s5.intern(); String s7 = "H"; String s8 = "ello"; String s9 = s7 + s8; System.out.println(s1 == s2); // true System.out.println(s1 == s3); // true System.out.println(s1 == s4); // false System.out.println(s1 == s9); // false System.out.println(s4 == s5); // false System.out.println(s1 == s6); // true
まず、Java で == 演算子を直接使用する場合、比較されるのは 2 つの文字列の内容ではなく、参照アドレスであることを説明します。内容を比較します。
s1 == s2 は非常に分かりやすいです。s1 と s2 に値を代入するとき、どちらも文字列リテラルを使用します。平たく言えば、文字列を直接書き出すことを意味します。コンパイル時に、この種のリテラルは、再利用を実現するためにクラス ファイルの定数プールに直接配置されます。ランタイム定数プールをロードした後、s1 と s2 は同じメモリ アドレスを指すため、それらは等しくなります。
s1 == s3 には落とし穴があります。s3 は動的に結合された文字列ですが、結合に関係するすべての部分は既知のリテラルです。コンパイル中に、この結合は最適化されます。コンパイラはそれを直接綴ります。つまり、クラスファイルでは String s3 = "Hel" "lo"; が String s3 = "Hello"; に最適化され、s1 == s3 が成立します。
s1 == s4 は確かに等しくありません。s4 も結合されていますが、新しい String("lo") 部分は既知のリテラルではなく、予測不可能な部分です。コンパイラはそれを最適化しません。結果文字列不変定理と組み合わせると、s4 がどこに割り当てられるかは誰にも分からないため、アドレスは異なるはずです。アイデアを明確にするために簡単な図を示します:
s1 == s9 は等しくありません、そして理由は同様です。s7 と s8 は値を割り当てるときに文字列リテラルを使用しますが、それらが結合されるときはs9 に, 2 つの変数として, s7 と s8 は予測できません. 結局のところ, コンパイラはコンパイラであり, インタプリタとして使用できないため, 最適化は行われません. 実行されると, 新しい文字列は s7 と s8 によって結合されますヒープ内のアドレスになりますが、メソッド領域の定数プール内の s1 アドレスと同じにすることはできません。
s4 == s5 は説明の必要はありません。絶対に等しくありません。両方ともヒープ内にありますが、アドレスが異なります。
s1 == s6 これら 2 つの等価性は、完全にインターン メソッドによるものです。s5 はヒープ内にあり、コンテンツは Hello です。インターン メソッドは、Hello 文字列を定数プールに追加して、それを返そうとします。定数プールにはすでに Hello 文字列が存在するため、インターン メソッドはアドレスを直接返し、s1 はコンパイル中にすでに定数プールを指しているため、s1 と s6 は同じアドレスを指しており、等しくなります。
この時点で、非常に重要な 3 つの結論を導き出すことができます。
定数プールをよりよく理解するには、コンパイル時の動作に注意を払う必要があります。
ランタイム定数プールの定数は、基本的に各クラス ファイルの定数プールから取得されます。
プログラムの実行中、定数が定数プールに手動で追加されない限り (インターン メソッドの呼び出しなど)、jvm は定数を定数プールに自動的に追加しません。
上記には文字列定数プールのみが関係します。実際には、整数定数プール、浮動小数点定数プールなどもありますが、それらはすべて似ています。ただし、数値定数プールに手動で定数を追加することはできません。タイプ定数プールです。定数プールの定数はプログラムの起動時に決定されます。たとえば、整数定数プールの定数範囲は -128 ~ 127 です。定数プールではこの範囲の数値のみを使用できます。
実践
理論についてはここまで述べたので、実際の定数プールについて触れてみましょう。
前に述べたように、クラス ファイルには静的定数プールがあります。この定数プールはコンパイラによって生成され、Java ソース ファイルにリテラルを格納するために使用されます (この記事ではリテラルのみに焦点を当てます)。次の Java コードがあります:
String s = "hi";
为了方便起见,就这么简单,没错!将代码编译成class文件后,用winhex打开二进制格式的class文件。如图:
简单讲解一下class文件的结构,开头的4个字节是class文件魔数,用来标识这是一个class文件,说白话点就是文件头,既:CA FE BA BE。
紧接着4个字节是java的版本号,这里的版本号是34,因为笔者是用jdk8编译的,版本号的高低和jdk版本的高低相对应,高版本可以兼容低版本,但低版本无法执行高版本。所以,如果哪天读者想知道别人的class文件是用什么jdk版本编译的,就可以看这4个字节。
接下来就是常量池入口,入口处用2个字节标识常量池常量数量,本例中数值为00 1A,翻译成十进制是26,也就是有25个常量,其中第0个常量是特殊值,所以只有25个常量。
常量池中存放了各种类型的常量,他们都有自己的类型,并且都有自己的存储规范,本文只关注字符串常量,字符串常量以01开头(1个字节),接着用2个字节记录字符串长度,然后就是字符串实际内容。本例中为:01 00 02 68 69。
接下来再说说运行时常量池,由于运行时常量池在方法区中,我们可以通过jvm参数:-XX:PermSize、-XX:MaxPermSize来设置方法区大小,从而间接限制常量池大小。
假设jvm启动参数为:-XX:PermSize=2M -XX:MaxPermSize=2M,然后运行如下代码:
//保持引用,防止自动垃圾回收 List<String> list = new ArrayList<String>(); int i = 0; while(true){ //通过intern方法向常量池中手动添加常量 list.add(String.valueOf(i++).intern()); }
程序立刻会抛出:Exception in thread "main" java.lang.outOfMemoryError: PermGen space异常。PermGen space正是方法区,足以说明常量池在方法区中。
在jdk8中,移除了方法区,转而用Metaspace区域替代,所以我们需要使用新的jvm参数:-XX:MaxMetaspaceSize=2M,依然运行如上代码,抛出:java.lang.OutOfMemoryError: Metaspace异常。同理说明运行时常量池是划分在Metaspace区域中。具体关于Metaspace区域的知识,请读者自行搜索。
更多java知识请关注java基础教程栏目。
以上がJava定数プールの詳細なグラフィックとテキストの説明の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

ホットAIツール

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

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

Undress AI Tool
脱衣画像を無料で

Clothoff.io
AI衣類リムーバー

Video Face Swap
完全無料の AI 顔交換ツールを使用して、あらゆるビデオの顔を簡単に交換できます。

人気の記事

ホットツール

メモ帳++7.3.1
使いやすく無料のコードエディター

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

ゼンドスタジオ 13.0.1
強力な PHP 統合開発環境

ドリームウィーバー CS6
ビジュアル Web 開発ツール

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

ホットトピック











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

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

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

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

PHP and Python each have their own advantages, and the choice should be based on project requirements. 1.PHPは、シンプルな構文と高い実行効率を備えたWeb開発に適しています。 2。Pythonは、簡潔な構文とリッチライブラリを備えたデータサイエンスと機械学習に適しています。

PHPは、サーバー側で広く使用されているスクリプト言語で、特にWeb開発に適しています。 1.PHPは、HTMLを埋め込み、HTTP要求と応答を処理し、さまざまなデータベースをサポートできます。 2.PHPは、ダイナミックWebコンテンツ、プロセスフォームデータ、アクセスデータベースなどを生成するために使用され、強力なコミュニティサポートとオープンソースリソースを備えています。 3。PHPは解釈された言語であり、実行プロセスには語彙分析、文法分析、編集、実行が含まれます。 4.PHPは、ユーザー登録システムなどの高度なアプリケーションについてMySQLと組み合わせることができます。 5。PHPをデバッグするときは、error_reporting()やvar_dump()などの関数を使用できます。 6. PHPコードを最適化して、キャッシュメカニズムを使用し、データベースクエリを最適化し、組み込み関数を使用します。 7

Java は、初心者と経験豊富な開発者の両方が学習できる人気のあるプログラミング言語です。このチュートリアルは基本的な概念から始まり、高度なトピックに進みます。 Java Development Kit をインストールしたら、簡単な「Hello, World!」プログラムを作成してプログラミングを練習できます。コードを理解したら、コマンド プロンプトを使用してプログラムをコンパイルして実行すると、コンソールに「Hello, World!」と出力されます。 Java の学習はプログラミングの旅の始まりであり、習熟が深まるにつれて、より複雑なアプリケーションを作成できるようになります。
