なぜコンパイラ/JVM はオートボックス化を「正常に動作させる」ことができないのでしょうか?
-
25-09-2019 - |
質問
オートボクシングはかなり怖いです。違いは十分理解していますが、 ==
そして .equals
次のようなバグが発生するのは仕方がありません。
final List<Integer> foo = Arrays.asList(1, 1000);
final List<Integer> bar = Arrays.asList(1, 1000);
System.out.println(foo.get(0) == bar.get(0));
System.out.println(foo.get(1) == bar.get(1));
それは印刷されます
true
false
なぜ彼らはこのようなことをしたのでしょうか?これはキャッシュされた整数と関係がありますが、その場合、なぜプログラムで使用されるすべての整数をキャッシュしないのでしょうか?あるいは、なぜ JVM は常に自動的にプリミティブにアンボックスされないのでしょうか?
false false または true true を出力するほうがずっと良いでしょう。
編集
古いコードの破損については同意しません。持つことで foo.get(0) == bar.get(0)
true を返すと、すでにコードが壊れています。
これは、バイトコードで Integer を int に置き換えることによってコンパイラレベルで解決できませんか (null が割り当てられていない限り)
解決
- なぜいます。
毎の整数を-128 127キャッシュによるjava.かったことは、性能ます。なかったこの決定は、こうするパラメータである。な内蔵コードによっては、そのコードク上で稼働している時でした。趣味のコーディング、このかは関係ありませんが、企業コードでは、人が不調や訴訟が起こる。
- なぜならキャッシュのすべての整数での使用はどうすればいいですか?
すべての整数でキャッシュするので、メモリの影響が甚大である。
- が記載されていないのはなぜ、JVMは常にオートunboxプリミティブ?
でのJVMできなかにあります。また、この変更が簡単に壊れレガシーコード搭載されていないという扱います。
場合、JVMを自動的にunboxedるプリミティブに電話==この問題を実際になり混乱している。今必要なものを忘れないでほしい。==常に比較しオブジェクト参照の場合を除き、オブジェクトunboxed.この原因となり変な混乱の場合のようにつまされているものと考えられる。
というよりも安心くことを覚えておいてくださいこの規則ではなく:
ない を比較しにオブジェクト==なければなろうとするものと比較し、その参照です。そうすれば、必ず思いつかないシナリオんで走るのが課題です。
他のヒント
あなたはすべてのInteger
が抑留のためのオーバーヘッド実施した場合になりますどのように悪いパフォーマンスを想像できますか?またnew Integer
のために仕事をしません。
Java言語(ないJVMの問題)は、常に自動Unboxのできないコードは、事前に1.5のJava用に設計されたので、まだ仕事ます。
べきバイトの範囲内Integer
sは、同じオブジェクトです。バイト範囲外のInteger
sではありません。すべての整数がキャッシュされるとしたら、メモリが必要と想像します。
からここを
このすべての魔法の結果は、あなたが主にいくつかの注意事項で、int型と整数間の区別を無視することができるということです。整数式はNULL値を持つことができます。あなたのプログラムがautounboxヌルにしようとすると、それは、NullPointerExceptionがスローされます。 ==演算子を行なうには、整数式の同一性比較とint型の式の値の等価比較を参照します。それは自動的に行われても最後に、ボクシングとアンボクシングに関連したパフォーマンスコストがあります。
あなたは完全にオートボクシングスキップした場合、あなたはまだ、この動作を取得します。
final List<Integer> foo =
Arrays.asList(Integer.valueOf( 1 ), Integer.valueOf( 1000 ));
final List<Integer> bar =
Arrays.asList(Integer.valueOf( 1 ), Integer.valueOf( 1000 ));
System.out.println(foo.get(0) == bar.get(0)); // true
System.out.println(foo.get(1) == bar.get(1)); // false
あなたが特定の行動をしたい場合は、より明示的にしてます:
final List<Integer> foo =
Arrays.asList( new Integer( 1 ), new Integer( 1000 ));
final List<Integer> bar =
Arrays.asList( new Integer( 1 ), new Integer( 1000 ));
System.out.println(foo.get(0) == bar.get(0)); // false
System.out.println(foo.get(1) == bar.get(1)); // false
これはEclipseは、デフォルトでは警告としてオートボクシングた理由です。
Java に関する本を書いている人も含め、多くの人がこの問題で問題を抱えています。
で プロ Java プログラミング, ほんの数インチ下では、著者が IdentityHashMap のキーとして自動ボックス化された整数を使用する際の問題について語っており、彼は WeakHashMap で自動ボックス化された整数キーを使用しています。彼が使用するサンプル値は 128 より大きいため、ガベージ コレクション呼び出しは成功します。ただし、誰かが彼の例を使用して 128 より小さい値を使用した場合、彼の例は失敗します (キーが永続的にキャッシュされているため)。
あなたが書くとき
foo.get(0)
コンパイラは、リストを作成したかは問題ではありません。それだけでリストfooのコンパイル時の型を調べます。だから、リストであれば、行うことになっているとして、<整数>、それは、一覧<整数>としてあることを扱いますし、リストの<整数>のGET()は常に整数を返します。使用したい場合は==、あなたは
を記述する必要がありますSystem.out.println(foo.get(0).intValue() == bar.get(0).intValue());
ない
System.out.println(foo.get(0) == bar.get(0));
それは全く別の意味を持っているので。