サーチ…


前書き

Autoboxingは、Javaコンパイラがプリミティブ型とそれに対応するオブジェクトラッパークラスの間で行う自動変換です。例、int - > Integer、double - > Double ...の変換変換が逆の場合は、これをunboxingと呼びます。通常、これは、コレクション以外のオブジェクトを保持できないコレクションで使用されます。ボクシングプリミティブ型はコレクション内で設定する前に必要です。

備考

オートボクシングでは、コードで頻繁に使用するとパフォーマンスの問題が発生する可能性があります。

intとIntegerを同じ意味で使用する

ユーティリティクラスでジェネリック型を使用する場合、オブジェクト型として指定されている場合、それらのプリミティブ型と等しくないので、数値型はそれほど役に立ちません。

List<Integer> ints = new ArrayList<Integer>();
Java SE 7
List<Integer> ints = new ArrayList<>();

幸いなことに、して評価する式intの代わりに使用することができるIntegerが必要なとき。

for (int i = 0; i < 10; i++)
    ints.add(i);

ints.add(i);ステートメントは次のものと同等です。

ints.add(Integer.valueOf(i));

また、 Integer#valueOfプロパティは、数値キャッシュの範囲内にあるときにJVMによってキャッシュされる同じIntegerオブジェクトを保持するなど、保持されます。

これは以下の場合にも適用されます:

  • byteByte
  • shortShort
  • floatFloat
  • doubleDouble
  • longLong
  • charCharacter
  • booleanBoolean

しかし、あいまいな状況では注意が必要です。次のコードを考えてみましょう:

List<Integer> ints = new ArrayList<Integer>();
ints.add(1);
ints.add(2);
ints.add(3);
ints.remove(1); // ints is now [1, 3]

java.util.Listインタフェースには、 remove(int index)Listインタフェースメソッド)とremove(Object o)java.util.Collectionから継承されたメソッド)の両方が含まれています。この場合、ボクシングは行われず、 remove(int index)が呼び出されます。

範囲の値を持つ整数をオートボクシングにより生じる奇妙なJavaコードの動作の一の以上の実施例-128127

Integer a = 127;
Integer b = 127;
Integer c = 128;
Integer d = 128;
System.out.println(a == b); // true
System.out.println(c <= d); // true
System.out.println(c >= d); // true
System.out.println(c == d); // false

これが起こる>=演算子は、暗黙的に呼び出しintValue()戻りintながら== 参照ではなく、比較int値。

デフォルトでは、Javaの値は[-128, 127]範囲でキャッシュされるため、演算子==機能するのは、この範囲のIntegersは、値が同じ場合に同じオブジェクトを参照するためです。キャッシング可能範囲の最大値は、 -XX:AutoBoxCacheMax JVMオプションを使用して定義できます。つまり、 -XX:AutoBoxCacheMax=1000でプログラムを実行すると、次のコードはtrue

Integer a = 1000;
Integer b = 1000;
System.out.println(a == b); // true

if文のブール値の使用

自動アンボックスのため、 if文でBooleanを使用できます。

Boolean a = Boolean.TRUE;
if (a) { // a gets converted to boolean
    System.out.println("It works!");
}

それはのために働くwhiledo whileとにおける条件forにも記述が含まれます。

Booleannull場合、変換でNullPointerExceptionがスローされることに注意してください。

自動アンボクシングによってNullPointerExceptionが発生することがある

このコードをコンパイルする:

Integer arg = null;
int x = arg;

しかし、実行時に2行目のjava.lang.NullPointerExceptionでクラッシュします。

問題は、プリミティブintnull値を持つことができないということです。

これは最小限の例ですが、実際にはより洗練された形でよく現れます。 NullPointerExceptionは非常に直感的ではなく、しばしばそのようなバグの特定に役立つことはほとんどありません。

autoboxingとauto-unboxingに注意して、実行時にボックス化されていない値にnull値がないことを確認してください。

オートボクシングのメモリと計算上のオーバーヘッド

オートボクシングはかなりのメモリオーバーヘッドになる可能性があります。例えば:

Map<Integer, Integer> square = new HashMap<Integer, Integer>();
for(int i = 256; i < 1024; i++) {
    square.put(i, i * i); // Autoboxing of large integers
}

相当量のメモリを消費します(6kの実際のデータで約60kb)。

さらに、ボックス化された整数は、通常、メモリに追加のラウンドトリップを必要とし、CPUキャッシュの効率を低下させます。上記の例では、アクセスされるメモリは、メモリの全く異なる領域にある5つの異なる場所、 HashMapオブジェクト、2。マップのEntry[] tableオブジェクト、 Entryオブジェクト、4。エントリkeyオブジェクト(ボクシングプリミティブキー)、5.エントリvalueオブジェクト(ボクシングプリミティブ値)。

class Example {
  int primitive; // Stored directly in the class `Example`
  Integer boxed; // Reference to another memory location
}

読書boxedprimitiveのみにアクセスする2つのメモリアクセスを必要とする。

このマップからデータを取得すると、一見無邪気なコード

int sumOfSquares = 0;
for(int i = 256; i < 1024; i++) {
    sumOfSquares += square.get(i);
}

次のものと同等です。

int sumOfSquares = 0;
for(int i = 256; i < 1024; i++) {
    sumOfSquares += square.get(Integer.valueOf(i)).intValue();
}

通常、上記のコードは、 Map#get(Integer)操作ごとにIntegerオブジェクトの作成とガベージコレクションを行います。 (詳細は下記の注を参照してください)。

このオーバーヘッドを減らすために、いくつかのライブラリ 、ボクシングを必要としないプリミティブ型の最適化されたコレクションを提供します。ボクシングのオーバーヘッドを避けることに加えて、これらのコレクションではエントリあたり約4倍のメモリが必要になります。 Javaホットスポット 、ヒープではなくスタック上のオブジェクトを操作することでオートボクシングを最適化できる可能性がありますが、メモリのオーバーヘッドとその結果のメモリ間接参照を最適化することはできません。

Java 8ストリームには、ボクシングを必要としないIntStreamなどのプリミティブデータ型用の最適化されたインタフェースもあります。

注:典型的なJavaランタイムは、 valueOfファクトリメソッドおよびオートボクシングによって使用されるIntegerおよびその他のプリミティブラッパーオブジェクトの単純なキャッシュを保持します。 Integerの場合、このキャッシュのデフォルトの範囲は-128〜+127です。 JVMの中には、キャッシュサイズ/範囲を変更するためのJVMコマンドラインオプションがあります。

異なるケースIntegerとintを区別なく使用できる場合

ケース1:メソッドの引数の代わりに使用しています。

メソッドが引数としてラッパークラスのオブジェクトを必要とする場合、引数はそれぞれのプリミティブ型の変数にやりとりすることができます。

例:

int i;
Integer j;
void ex_method(Integer i)//Is a valid statement
void ex_method1(int j)//Is a valid statement

ケース2:戻り値を渡しているとき:

メソッドがプリミティブ型変数を返すとき、対応するラッパークラスのオブジェクトは戻り値として同じ意味で渡され、逆も同様です。

例:

int i;
Integer j;
int ex_method()
{...
return j;}//Is a valid statement
Integer ex_method1()
{...
return i;//Is a valid statement
}

ケース3:操作を実行中。

数値に対して演算を行うときはいつでも、それぞれのラッパークラスのプリミティブ型変数とオブジェクトは同じ意味で使用できます。

int i=5;
Integer j=new Integer(7);
int k=i+j;//Is a valid statement
Integer m=i+j;//Is also a valid statement

落とし穴 :ラッパークラスのオブジェクトに値を初期化または割り当てることを忘れないでください。

ラッパークラスオブジェクトとプリミティブ変数を同じ意味で使用している間に、ラッパークラスオブジェクトに値を初期化したり割り当てたりすることを忘れることはありません。実行時にnullポインター例外が発生する可能性があります。

例:

public class Test{
    Integer i;
    int j;
    public void met()
    {j=i;//Null pointer exception
    SOP(j);
    SOP(i);}   
    public static void main(String[] args)
    {Test t=new Test();
    t.go();//Null pointer exception
    }

上記の例では、オブジェクトの値は割り当てられていないため、初期化されていないため、実行時にプログラムはNULLポインタ例外になります。上記の例から明らかなように、objectの値は決して初期化されず、割り当てられません。



Modified text is an extract of the original Stack Overflow Documentation
ライセンスを受けた CC BY-SA 3.0
所属していない Stack Overflow