ホームページ >Java >&#&チュートリアル >Java仮想マシン:ランタイム定数プール

Java仮想マシン:ランタイム定数プール

巴扎黑
巴扎黑オリジナル
2017-06-26 09:56:061505ブラウズ

1. ランタイム定数プールの概要

ランタイム定数プール (Runtime Constant Pool) はメソッド領域の一部です。 クラスクラスのバージョン、フィールド、メソッド、インターフェース、その他の説明などの情報に加えて、コンパイル中に生成されるさまざまなリテラルやシンボルを格納するために使用される定数プール (定数プールテーブル) という情報もあります。参考までに、コンテンツのこの部分は、クラスがロードされた後、定数プールに保存されます。

ランタイム定数は定数に対して相対的なものであり、ダイナミクスという重要な機能があります。もちろん、同じ値を持つ動的定数は、通常説明する定数とはソースが異なるだけですが、それらはすべてプール内の同じメモリ領域に格納されます。 Java 言語では、定数がコンパイル中にのみ生成される必要はありません。新しい定数は実行時にも生成され、これらの定数は実行時定数プールに配置されます。ここで説明する定数には、基本型パッケージング クラス (パッケージング クラスは浮動小数点型を管理せず、整数は -128 ~ 127 のみを管理します) および String (String.intern() を介して String を強制的に配置することもできます) が含まれます。メソッドを定数プールに追加)

2. クラス ファイル内の情報定数プール

クラス ファイル構造では、最初の 4 バイトはメジック番号を格納するために使用されます。メジック番号は、ファイルがメソッドによって受け入れられるかどうかを判断するために使用されます。 JVM の後に続く 4 バイトはバージョン番号を格納するために使用され、最初の 2 バイトはマイナー バージョン番号を格納し、最後の 2 バイトはメジャー バージョン番号を格納し、定数プールは定数の格納に使用されます。定数プールが固定されていない場合、エントリは定数プールの容量カウント値を格納する U2 タイプのデータ (constant_pool_count) を配置します。

定数プールは主に、リテラルとシンボリック参照という 2 つの主要なタイプの定数を保存するために使用されます。リテラルは、テキスト文字列、final として宣言された定数値など、Java 言語レベルの定数の概念に相当します。 、シンボリック参照は、次の 3 種類の定数を含むコンパイル原則の概念です:

  • クラスとインターフェイスの完全修飾名

  • フィールド名と記述子

  • メソッド名と記述子

3 . 定数プールの利点

定数プールは、システムのパフォーマンスに影響を与えるオブジェクトの頻繁な作成と破棄を回避し、オブジェクトの共有を実現します。たとえば、文字列定数プールは、コンパイル段階ですべての文字列リテラルを定数プールに置きます。

  • メモリ領域を節約: 定数プール内の同じ文字列定数はすべてマージされ、1 つの領域のみを占有します。

  • 実行時間を節約する: 文字列を比較する場合、== は、equals() よりも高速です。 2 つの参照変数の場合、== を使用して参照が等しいかどうかを判断するだけでなく、実際の値が等しいかどうかも判断できます。

二重等号の意味==

  • 基本データ型間に二重等号を適用し、その数値を比較します。

  • メモリ内のストレージアドレスを比較するために、複合データ型 (クラス) 間に二重等号が適用されます。

4. 基本型パッケージング クラスと定数プール

Java の基本型パッケージング クラスのほとんどは、定数プール テクノロジ、つまり Byte、Short、Integer、Long、Character、Boolean を実装しています。これら 5 つのパッケージ化クラスは、デフォルトで値 [-128, 127] を持つ対応するタイプのキャッシュ データを作成しますが、新しいオブジェクトはこの範囲を超えて作成されます。 2 つの浮動小数点型ラッパー クラス Float と Double は、定数プール テクノロジ を実装していません。

1) 整数および定数プール

Java仮想マシン:ランタイム定数プール
Integer i1 = 40;
Integer i2 = 40;
Integer i3 = 0;
Integer i4 = new Integer(40);
Integer i5 = new Integer(40);
Integer i6 = new Integer(0);

System.out.println("i1=i2   " + (i1 == i2));
System.out.println("i1=i2+i3   " + (i1 == i2 + i3));
System.out.println("i1=i4   " + (i1 == i4));
System.out.println("i4=i5   " + (i4 == i5));
System.out.println("i4=i5+i6   " + (i4 == i5 + i6));  
System.out.println("40=i5+i6   " + (40 == i5 + i6));


i1=i2   true
i1=i2+i3   true
i1=i4   false
i4=i5   false
i4=i5+i6   true
40=i5+i6   true
Java仮想マシン:ランタイム定数プール
説明:
  • Integer i1=40; の場合、Java はコードを Integer i1=Int に直接カプセル化します。 valueOf をコンパイルしています。 (40); これにより、定数プールのオブジェクトが使用されます。

  • Integer i1 = new Integer(40); この場合、新しいオブジェクトが作成されます。

  • ステートメント i4 == i5 + i6。+ 演算子は Integer オブジェクトに適用されないため、まず、i5 と i6 が自動アンボックス化操作を実行し、値 を追加します。つまり、i4 == 40 です。次に、Integer オブジェクトを数値と直接比較することはできないため、i4 は自動的にボックスを解除し、int 値 40 に変換します。最後に、このステートメントは数値比較のために 40 == 40 に変換されます。

2) 文字列と定数プール - 通常のメソッドの代入

Java仮想マシン:ランタイム定数プール
String str1 = "abcd";
String str2 = new String("abcd");
System.out.println(str1==str2);//false

String str1 = "str";
String str2 = "ing";
String str3 = "str" + "ing";
String str4 = str1 + str2;
System.out.println("string" == "str" + "ing");// true
System.out.println(str3 == str4);//false

String str5 = "string";
System.out.println(str3 == str5);//true
Java仮想マシン:ランタイム定数プール
解释:
  • "abcd"是在常量池中拿对象,new String("abcd")是直接在堆内存空间创建一个新的对象。只要使用new方法,便需要创建新的对象

  • 连接表达式 +,只有使用引号包含文本的方式创建的String对象之间使用“+”连接产生的新对象才会被加入常量池中

  • 对于字符串变量的“+”连接表达式,它所产生的新对象都不会被加入字符串池中,其属于在运行时创建的字符串,具有独立的内存地址,所以不引用自同一String对象。

3)String与常量池-静态方法赋值

Java仮想マシン:ランタイム定数プール
public static final String A; // 常量A
public static final String B;    // 常量B
static {  
   A = "ab";  
   B = "cd";  
}  
public static void main(String[] args) {  
// 将两个常量用+连接对s进行初始化  
String s = A + B;  
String t = "abcd";  
if (s == t) {  
    System.out.println("s等于t,它们是同一个对象");  
  } else {  
    System.out.println("s不等于t,它们不是同一个对象");  
  }  
}
Java仮想マシン:ランタイム定数プール
解释:

s不等于t,它们不是同一个对象。A和B虽然被定义为常量,但是它们都没有马上被赋值。在运算出s的值之前,他们何时被赋值,以及被赋予什么样的值,都是个变数。因此A和B在被赋值之前,性质类似于一个变量。那么s就不能在编译期被确定,而只能在运行时被创建了。

4)String与常量池-intern方法

Java仮想マシン:ランタイム定数プール
public static void main(String[] args) {
  String s1 = new String("计算机");
  String s2 = s1.intern();
  String s3 = "计算机";
  System.out.println("s1 == s2? " + (s1 == s2));
  System.out.println("s3 == s2? " + (s3 == s2));
}
s1 == s2? false
s3 == s2? true
Java仮想マシン:ランタイム定数プール
解释:

String的intern()方法会查找在常量池中是否存在一份equal相等的字符串,如果有则返回该字符串的引用,如果没有则添加自己的字符串进入常量池

5)String与常量池-延伸

String s1 = new String("xyz"); //创建了几个对象?
解释:

考虑类加载阶段和实际执行时。

  • 类加载对一个类只会进行一次。”xyz”在类加载时就已经创建并驻留了(如果该类被加载之前已经有”xyz”字符串被驻留过则不需要重复创建用于驻留的”xyz”实例)。驻留的字符串是放在全局共享的字符串常量池中的。

  • 在这段代码后续被运行的时候,”xyz”字面量对应的String实例已经固定了,不会再被重复创建。所以这段代码将常量池中的对象复制一份放到heap中,并且把heap中的这个对象的引用交给s1 持有

这条语句创建了2个对象。

以上がJava仮想マシン:ランタイム定数プールの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

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