13

オートボクシングはかなり怖いです。==私はとの違いを完全に理解して.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 を印刷する方がずっと良いでしょう。

編集

古いコードの破損については同意しません。trueをfoo.get(0) == bar.get(0)返すことで、すでにコードが壊れています。

これは、バイト コードで Integer を int に置き換えることによってコンパイラ レベルで解決できませんか (null が割り当てられない限り)。

4

6 に答える 6

12
  • なぜ彼らはこのようにしたのですか?

-128 から 127 までのすべての整数は、Java によってキャッシュされます。彼らはおそらく、パフォーマンス上の利点のためにこれを行いました。彼らが今この決定に戻りたいと思ったとしても、そうする可能性は低い. 誰かがこれに依存してコードを作成した場合、そのコードは取り出したときに壊れます。趣味のコーディングの場合、これは問題にならないかもしれませんが、エンタープライズ コードの場合、人々は動揺し、訴訟が発生します。

  • プログラムで使用されるすべての整数をキャッシュしないのはなぜですか?

メモリへの影響が膨大になるため、すべての整数をキャッシュすることはできません。

  • JVM が常にプリミティブに自動的にアンボックスしないのはなぜですか?

JVMはあなたが何を望んでいたかを知ることができないためです。また、この変更により、このケースを処理するように構築されていないレガシー コードが簡単に壊れる可能性があります。

JVM が == の呼び出しでプリミティブに自動的にボックス化解除される場合、この問題は実際にはさらに混乱を招きます。ここで、オブジェクトをボックス化解除できない限り、== は常にオブジェクト参照を比較することを覚えておく必要があります。これにより、上で述べたようなさらに奇妙な混乱を招くケースが発生します。

これについてあまり心配するのではなく、代わりに次のルールを覚えておいてください。

オブジェクトを参照によって比較するつもりでない限り、決してオブジェクトを == と比較しないでください。そうすれば、あなたが問題に遭遇するシナリオは考えられません。

于 2010-04-08T19:20:09.760 に答える
7

Integerすべての人が強制収容のために諸経費を負担した場合、パフォーマンスがどれほど低下するか想像できますか? にも機能しませんnew Integer

Java 言語 (JVM の問題ではない) は、1.5 より前の Java 用に設計されたコードが引き続き機能するため、常に自動アンボックス化できるとは限りません。

于 2010-04-08T19:04:18.930 に答える
5

Integerバイト範囲内の s はキャッシュされるため、同じオブジェクトです。Integerバイト範囲外の s はそうではありません。すべての整数をキャッシュする場合、必要なメモリを想像してください。

そしてここから

このすべての魔法の結果、int と Integer の違いはほとんど無視できますが、いくつかの注意事項があります。整数式には null 値を含めることができます。プログラムが null を autounbox しようとすると、NullPointerException がスローされます。== 演算子は、整数式で参照同一性比較を実行し、int 式で値の等価性比較を実行します。最後に、ボックス化とボックス化解除が自動的に行われる場合でも、パフォーマンス コストが発生します。

于 2010-04-08T19:11:12.857 に答える
4

オートボクシングを完全にスキップしても、この動作は引き続き発生します。

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 がデフォルトで警告としてオートボクシングを行う理由です。

于 2010-04-08T19:28:59.043 に答える
3

Java に関する本を書いている人でさえ、多くの人がこの問題に悩まされています。

Pro Java Programmingでは、著者が自動ボックス化された Integer を IdentityHashMap のキーとして使用する際の問題について語っています。彼は WeakHashMap で自動ボックス化された整数キーを使用しています。彼が使用する例の値は 128 より大きいため、ガベージ コレクションの呼び出しは成功します。ただし、誰かが彼の例を使用して 128 より小さい値を使用すると、彼の例は失敗します (キーがパーマ キャッシュされているため)。

于 2010-04-08T23:15:58.577 に答える
2

あなたが書くとき

foo.get(0)

コンパイラは、リストをどのように作成したかは問題ではありません。List foo のコンパイル時の型のみを調べます。そのため、それが List<Integer> である場合、それが想定どおりに List<Integer> として扱われ、List<Integer> の get() は常に Integer を返します。== を使用する場合は、次のように記述する必要があります。

System.out.println(foo.get(0).intValue() == bar.get(0).intValue());

いいえ

System.out.println(foo.get(0) == bar.get(0));

意味が全然違うから。

于 2011-06-01T08:26:58.827 に答える