web-dev-qa-db-ja.com

整数ラッパークラスを使用して作成されるオブジェクトの数

Integer i = 3; 
i = i + 1; 
Integer j = i; 
j = i + j; 

上記のサンプルコードのステートメントの結果として作成されるオブジェクトの数とその理由は?作成されたオブジェクトの数を確認できるIDE)はありますか(デバッグモードで)。

59
Syamesh K

驚くべきことに、答えはゼロです。

-128〜+127のすべてのIntegersは、JVMによって事前に計算されます。

コードは、これらの既存オブジェクトに対するreferencesを作成します。

101
Bathsheba

厳密に正しい答えは、作成されるIntegerオブジェクトの数はindeterminateです。 0〜3、または2561 またはそれ以上2、 応じて

  • Javaプラットフォーム3
  • このコードが初めて実行されるかどうか、および
  • (潜在的に)int値のボックス化に依存する他のコードがその前に実行されるかどうか4

-128〜127のInteger値は、precomputedである必要はありません。実際、ボクシング変換を指定した JLS 5.1.7 は次のように述べています。

ボックス化される値pが-128〜127(3.10.1)を含むint型の整数リテラルである場合、aとbを2つのボックス化変換の結果とします。常にa == bです。

注意すべき2つのこと:

  • JLSのみrequires>> literals <<の場合。
  • JLSは、値のキャッシュeagerを強制しません。レイジーキャッシングは、JLSの動作要件も満たしています。

Integer.valueof(int)のjavadocでさえ、結果が熱心にキャッシュされることをspecifyしません。

Java Java.lang.IntegerのSEソースコードをJava 6から8まで調べた場合、現在のJava SE実装戦略は値を事前に計算することですが、さまざまな理由(上記を参照)で、「オブジェクトの数」の質問に明確な答えを出すにはまだ十分ではありません。


1-上記のコードの実行がJavaのバージョンでIntegerのクラス初期化をトリガーすると、クラス初期化中にキャッシュが積極的に初期化されます。

2-キャッシュがJVM仕様に必要なサイズよりも大きい場合、さらに大きくなる可能性があります。 Javaの一部のバージョンでは、JVMオプションを使用してキャッシュサイズを増やすことができます。

3-ボクシングを実装するためのプラットフォームの一般的なアプローチに加えて、コンパイラーは、コンパイル時に計算の一部またはすべてを実行できるか、完全に最適化することができることを発見できます。

4-このようなコードは、整数キャッシュの遅延初期化または熱心な初期化をトリガーできます。

60
Stephen C

まず第一に:他の人が既に述べたように、あなたが探している答えは_0_です。

しかし、もう少し詳しく見ていきましょう。スティーブンがメンチオニングしたように、それはあなたがそれを実行する時間に依存します。キャッシュは実際には遅延初期化されるためです。

Java.lang.Integer.IntegerCacheのドキュメントを見ると:

キャッシュは最初の使用時に初期化されます。

これは、実際に作成した整数を呼び出すのが初めての場合:

  • 256個の整数オブジェクト(またはそれ以上:以下を参照)
  • 1整数を格納する配列のオブジェクト
  • クラス(およびメソッド/フィールド)の保存に必要なオブジェクトを無視しましょう。とにかくメタスペースに保存されます。

2回目にそれらを呼び出すと、0個のオブジェクトが作成されます。


数字を少し大きくすると、事態はさらに面白くなります。例えば。次の例で:

_Integer i = 1500; 
_

有効なオプションは次のとおりです:0、1、または1629から2147483776までの任意の数値(今回は作成された整数値のみをカウントします。なぜですか?整数キャッシュ定義の次の文に答えがあります。

キャッシュのサイズは-XX:AutoBoxCacheMax =オプションで制御できます。

したがって、実際に実装されるキャッシュのサイズを変えることができます。

つまり、上記の行に到達できます。

  • 1:キャッシュが1500より小さい場合、新しいオブジェクト
  • 0:キャッシュが以前に初期化され、1500が含まれる場合の新しいオブジェクト
  • 1629:new(整数)-キャッシュがちょうど1500に設定され、まだ初期化されていない場合のオブジェクト。次に、-128〜1500の整数値が作成されます。
  • 上記の文のように、ここでは最大Integer.MAX_VALUE + 129の整数オブジェクトに到達します。これは2147483776です。

覚えておいてください:これはOracle/Open JDKでのみ保証されます(バージョン7および8をチェックしました)

ご覧のとおり、完全に正しい答えを得るのはそれほど簡単ではありません。しかし、_0_と言うだけで人々は幸せになります。


PS:menthonedパラメーターを使用すると、次のステートメントを真にすることができます:Integer.valueOf(1500) == 1500

17
Denis Lukenich

コンパイラーはIntegerオブジェクトをintsにアンボックスし、それらに対して intValue() を呼び出して演算を行い、 Integer.valueOfを呼び出します は、int変数に割り当てられたときにIntegerの結果をボックス化するため、例は次と同等です。

Integer i = Integer.valueOf(3);
i = Integer.valueOf(i.intValue() + 1);
Integer j = i;
j = Integer.valueOf(i.intValue() + j.intValue());

割り当てj = i;は、新しいオブジェクトを作成しない、完全に通常のオブジェクト参照割り当てです。ボックス化もボックス化解除も行わず、Integerオブジェクトが不変である必要はありません。

valueOfメソッドは、オブジェクトをキャッシュし、特定の番号に対して毎回同じインスタンスを返すことができます。 int -128〜+127をキャッシュすることはrequiredです。 i = 3の開始番号については、すべての番号が小さく、キャッシュされることが保証されているため、作成する必要があるオブジェクトの数はです。厳密に言えば、valueOfはインスタンスをすべて事前に生成するのではなく、遅延してキャッシュすることが許可されているため、この例では最初にオブジェクトを作成する可能性がありますが、プログラム中にコードが繰り返し実行されると、作成されるオブジェクトの数毎回平均が0に近づく。

インスタンスがキャッシュされないより大きな数(i = 300など)で開始するとどうなりますか?その後、各valueOf呼び出しは1つの新しいIntegerオブジェクトを作成する必要があり、そのたびに作成されるオブジェクトの総数は3です。 。

または、多分それはまだゼロ、あるいは多分数百万です。コンパイラや仮想マシンは、その動作がそうでない限り、パフォーマンスや実装の理由でコードを書き換えることができます。変更されたので、結果を使用しない場合、上記のコードを完全に削除できます。または、jを印刷しようとすると、jは、上記のスニペットの後に常に同じ定数値になるため、コンパイル時にすべての算術を行い、定数値を出力します。コードを実行するために舞台裏で行われる実際の作業量は常に実装の詳細。)

5
Boann

Integer.valueOf(int i)メソッドをデバッグして、自分で調べることができます。このメソッドは、コンパイラによるオートボクシングプロセスによって呼び出されます。

2
Cootri