Javaでのオートボクシングとアンボクシング

今日は、オートボクシングとアンボクシングについてお話します。 これはJDK 5に加えられた重要な変更の1つです。開発者はよりクリーンなコードを記述できますが、このメカニズムの操作を誤解するとパフォーマンスが低下する可能性があります。



オートパック



これは、このタイプのオブジェクトが必要な場合に、同等のラッパークラスにプリミティブタイプを自動的にカプセル化するものです。 カプセル化と他のOOP原則に関するffriendからのすばらしい記事があります。



オートボクシングが発生します:

  1. 対応するラッパークラスの変数にプリミティブ型の値を割り当てる場合。
  2. 対応するラッパークラスを期待するメソッドのパラメーターにプリミティブ型を渡すとき。




JDK 5まで

public class Main { public static void main(String[] args) { Integer iOb = new Integer(7); Double dOb = new Double(7.0); Character cOb = new Character('a'); Boolean bOb = new Boolean(true); method(new Integer(7)); } public static void method(Integer iOb) { System.out.println("Integer"); } }
      
      





JDK 5以降

 public class Main { public static void main(String[] args) { Integer iOb = 7; Double dOb = 7.0; Character cOb = 'a'; Boolean bOb = true; method(7); } public static void method(Integer iOb) { System.out.println("Integer"); } }
      
      







自動開梱



これは、対応するプリミティブ型へのラッパークラスの変換です。 展開時にラッパークラスがnullの場合、 java.lang.NullPointerExceptionがスローされます。



開封が発生します:

  1. ラッパークラスのインスタンスを、対応するプリミティブ型の変数に割り当てるとき。
  2. 1つまたは両方の引数がラッパークラスのインスタンスである式(操作==および!=を除く)。
  3. ラッパークラスのオブジェクトを、適切なプリミティブ型が必要なメソッドに渡すとき。


よく見てみましょう。



1.割り当て時



JDK 5まで

 int i = iOb.intValue(); double d = dOb.doubleValue(); char c = cOb.charValue(); boolean b = bOb.booleanValue();
      
      





JDK 5以降

 int i = iOb; double d = dOb; char c = cOb; boolean b = bOb;
      
      





2.式で



算術演算子と比較演算子(exception == and!=)はプリミティブ型にのみ適用されるため、手動で展開する必要があり、式の可読性が大幅に低下し、式が大きくなり、コード全体が大きくなりました。

 Integer iOb1 = new Integer(5); Integer iOb2 = new Integer(7); System.out.println(iOb1.intValue() > iOb2.intValue());
      
      





自動展開のおかげで、変換メソッドを使用せずに式を安全に記述できます。 これで、Javaコンパイラはこれに従います。

 System.out.println(iOb1 > iOb2); System.out.println(iOb1 + iOb2);
      
      





== or!=演算子を使用してラッパークラスを比較する場合、比較は値ではなく参照によって行われ、混乱が発生する可能性があります。 たとえば、次のコードを実行すると何が表示されますか?

 Integer iOb1 = 100; Integer iOb2 = 100; System.out.println(iOb1 == iOb2); Integer iOb3 = new Integer(120); Integer iOb4 = new Integer(120); System.out.println(iOb3 == iOb4); Integer iOb5 = 200; Integer iOb6 = 200; System.out.println(iOb5 == iOb6);
      
      





回答:最初の場合-true、2番目と3番目-false。

最初のケースでは、静的メソッドjava.lang.Integer.valueOf(int)が実際に呼び出され、値を-128から127にキャッシュし(上限は変更可能)、再利用すると、いわゆるプール(初期化され、すぐに使用できるオブジェクトのセット)からそれらを取り出します) 2番目では、オブジェクトは明示的に作成されるため、異なる参照があります。



3.メソッドに渡されたとき



 public class Main { public static void main(String[] args) { Integer iOb = 10; method(iOb); } public static void method(int i) { System.out.println("int"); } }
      
      





intが表示されますが、対応するラッパークラスでのオーバーロードがメソッドに実装されている場合は呼び出されることに注意してください。

 public class Main { public static void main(String[] args) { Integer iOb = 10; method(iOb); } public static void method(int i) { System.out.println("int"); } public static void method(Integer iOb) { //    System.out.println("Integer"); } }
      
      





また、自動パッキングと自動パッキングはアレイでは機能しないことも忘れないでください。

 public class Main { public static void main(String[] args) { Integer[] iObs = new Integer[] {5, 10, 50, 2, 7}; method(iObs); //  } public static void method(int ... i) { System.out.println("int[]"); } }
      
      





悪いパフォーマンス



ラッパークラスは不変であるため、各自動パッケージ(プール値を除く)は新しいオブジェクトを作成し、不合理なメモリ消費につながる可能性があります。

 public static Integer sumBeforeInclusive(Integer number) { Integer iOb = number; if (number > 1) iOb += sumBeforeInclusive(number - 1); return iOb; }
      
      





プリミティブ型とそのラッパークラス



整数
  • バイト-バイト
  • ショート-ショート
  • int-整数
  • 長い-長い




浮動小数点数
  • フロート-フロート
  • ダブル-ダブル




キャラクター
  • char-キャラクター




ブール値
  • ブール-ブール





All Articles