8

Java の +=、-=、*=、/= 複合代入演算子(良い質問です:))を見つけましたが、よくわからない部分がありました。その質問からの借用:

int i = 5;
long l = 8;

その後i = i + l;、コンパイルされませんがi += l;、正常にコンパイルされます。

リンクされた質問に対する受け入れられた回答には、次のように記載されています。

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

これは、一度だけ評価される例外を除いてi += l;同じです。i = (int)((i) + (l));i

Alongは (IIRC でさえ保証されている) よりも長いint可能性があり、したがって、はるかに広い範囲の値を保持できます。

この状況では、ステートメントの実行中 (右辺値式の評価または代入) のある時点で必要な縮小変換が原因でデータ損失が非常に簡単に発生する可能性があることを考えるとi += l;、コンパイル時エラーまたは少なくとも警告ではないのはなぜですか?

4

3 に答える 3

14

基本的には、i += l書かれているかのようにコンパイルされるためですi = (int) (i + l)。および変数にint値を追加する場合にも同様の「驚き」があります。代入演算子は機能しますが、単純な加算演算子は機能しません。bytechar

于 2012-01-03T14:06:41.067 に答える
8

この状況では、ステートメントの実行中 (r 値式の評価または代入) のある時点で必要な縮小変換が原因で、データ損失が非常に簡単に発生する可能性があるため、i += l; はなぜですか? コンパイル時エラーまたは少なくとも警告ではありませんか?

あなたが言ったように、それはおそらくコンパイル時のエラーか、少なくとも警告のどちらかであるはずです。私が知っているほとんどの本やチュートリアルではx += y;x = x + y;. 正直なところ、JLS のセクション15.26.2 複合代入演算子で呼び出された区別を行うものは 1 つを除いて知りません。

Java Puzzlers: Traps, Pitfalls, and Corner Casesの第 2 章 (puzzle 9) で、著者 (Joshua Bloch と Neal Gafter)は、これが法的声明であるという宣言xを提供するように求めています。i

x += i;

これはそうではありません:

x = x + i;

質問に投稿した最初の 2 行のコードを含め、多くの解決策があります。byte著者は、型、short、およびの変数に複合代入演算子を使用しないように警告し、char型の変数にこれらの演算子を使用する場合intは、RHS 式がlongfloat、またはでないことを確認することをお勧めしますdouble

彼らは次の観察で締めくくります(強調は私のものです):

要約すると、複合代入演算子はサイレントにキャストを生成します。計算結果の型が変数の型より広い場合、生成されたキャストは危険な縮小キャストです。このようなキャストは、精度や大きさを暗黙のうちに破棄できます。 言語設計者にとって、複合代入演算子が目に見えないキャストを生成するのはおそらく間違いです。変数が計算の結果よりも狭い型を持つ複合代入は、おそらく不正であるはずです。

于 2012-02-16T00:17:40.580 に答える
1

この理由は、次のことができるようにするためです。

byte b = 1;

b += 1;

+= が b = b + 1 に展開された場合、式 "b + 1" は int 型であるため、式は型チェックを行いません。Java のすべての整数式は、たとえ 2 バイトを足し合わせたとしても、少なくとも int 型です。

public class Test {
  public static void main(String[] args) {
    byte b = 1;
    byte c = 2;
    byte d = b + c;
  }
}


Test.java:5: possible loss of precision
found   : int
required: byte
    byte d = b + c;
               ^
1 error
于 2012-02-16T09:29:13.317 に答える