13

驚いたことに、次のコードは警告なしでコンパイルされることがわかりました。

public void test()
{
    int value = 2000000000;
    long increment = 1000000000;
    value += increment;
}

予想どおり、これによりコンパイル時エラーが発生します。

public void test()
{
    int value = 2000000000;
    long increment = 1000000000;
    value = value + increment;
}

私はそれを調べました、そして確かに、JLS(セクション15.26.2)はこれを言っています:

E1 op = E2の形式の複合代入式は、E1 =(T)((E1)op(E2))と同等です。ここで、TはE1のタイプですが、E1は1回だけ評価されます。

これは私にはばかげているようです。なぜ彼らはここで明示的にキャストする必要性を感じたのですか?とにかく自動型変換が拡大を処理したようであり、このように自動的に縮小すると、整数のオーバーフローが発生することがほぼ保証されます。

4

3 に答える 3

4

ここに1つの説明があります:

割り当て(最初のコードスニペット)を行うと、LHSとRHSは互いに非常に独立している可能性があるため、Javaは型チェックを強制します。

ただし、複合演算子は、インクリメント演算子に似ています。+ =は、変数に新しい値を割り当てるのではなく、関連する変数の値を変更します。バイトを変更すると、結果としてバイトが期待されます。作業を楽にするために、javaは修飾子であるため、複合演算子の暗黙的な型変換を行います。

于 2011-03-30T01:47:58.603 に答える
2

複合代入演算子は、JLS(15.26.2)によって次のように指定されています。

"フォームの複合代入式はE1 op= E2

      E1 = (T)((E1) op (E2))`, 

ここで、TはE1のタイプですが、E1は1回だけ評価されます。」

この場合、E1はタイプintE2はタイプlongであり、opはタイプです+。したがって、これは次と同等です。

value = (int)(value + increment);

intanとaを追加すると、alongが与えられ、割り当て前にlongキャストバックされます。intそれはすべて問題ないので、コンパイルエラーはありません。

これと単純な割り当て(つまり)の違いはvalue = value + increment;、単純な割り当てには型キャストがないことです。


さて、なぜ彼らはそれをこのように定義したのですか?

その理由は、このような例を作成するためだと思います。

    byte b = ...
    b += 1;

型キャストb += 1がないと、コンパイルエラーが発生し、次のように記述する必要があります。

    b += (byte) 1;
于 2011-03-30T02:21:40.730 に答える
1

このリンクはあなたが提起した問題を分析しました。

精度が低下する可能性があるためのさまざまな動作

不愉快な驚きを避けるために、byte、short、またはchar型の変数に複合代入演算子を使用しないでください。int型の変数に複合代入演算子を使用する場合は、右側の式がlong、float、またはdouble型でないことを確認してください。float型の変数に複合代入演算子を使用する場合は、右側の式がdouble型でないことを確認してください。これらのルールは、コンパイラが危険なナローイングキャストを生成するのを防ぐのに十分です。

于 2011-03-30T02:01:17.547 に答える