1. 概要

このチュートリアルでは、Java複合演算子、それらのタイプ、およびJavaがそれらを評価する方法を見ていきます。

また、暗黙的なキャストがどのように機能するかについても説明します。

2. 複合代入演算子

代入演算子は、右側の結果を左側の変数に代入する二項演算子です。 最も単純なのは、“ =”代入演算子です。

int x = 5;

このステートメントは、新しい変数 x を宣言し、x5の値を割り当て、5を返します。

複合代入演算子は、算術演算またはビット演算を適用し、その演算の値を左側の変数に割り当てるためのより短い方法です。

たとえば、次の2つの乗算ステートメントは同等です。つまり、abの値は同じになります。

int a = 3, b = 3, c = -2;
a = a * c; // Simple assignment operator
b *= c; // Compound assignment operator

複合代入演算子の左側にある変数は、すでに宣言されている必要があることに注意してください。 つまり、複合演算子を使用して新しい変数を宣言することはできません。

「=」代入演算子と同様に、複合演算子は式の代入結果を返します。

long x = 1;
long y = (x+=2);

xyの両方が値3を保持します。

割り当て(x + = 2)は、2つのことを行います。1つは、変数 x の値に2を加算し、 3; になります。次に、割り当ての値。これも3です。

3. 複合代入演算子の種類

Javaは11個の複合代入演算子をサポートしています。 これらを算術演算子とビット演算子にグループ化できます。

算術演算子とそれらが実行する演算を見てみましょう。

  • インクリメント: + =
  • デクリメント:-=
  • 乗算: * =
  • 分割: / =
  • モジュラス:%=

次に、ビット演算子もあります。

  • AND、バイナリ: &=
  • 排他的論理和、バイナリ: ^ =
  • 包括的OR、バイナリ: | =
  • 左シフト、バイナリ: << =
  • 右シフト、バイナリ: >> =
  • 右シフトゼロフィル: >>> =

これらの操作のいくつかの例を見てみましょう。

// Simple assignment
int x = 5; // x is 5

// Incrementation
x += 5; // x is 10

// Decrementation
x -= 2; // x is 8

// Multiplication
x *= 2; // x is 16

// Modulus
x %= 3; // x is 1

// Binary AND
x &= 4; // x is 0

// Binary exclusive OR
x ^= 4; // x is 4

// Binary inclusive OR
x |= 8; // x is 12

ここでわかるように、これらの演算子を使用するための構文は一貫しています。

4. 複合割り当て操作の評価

Javaが複合操作を評価する方法は2つあります。

まず、左側のオペランドが配列でない場合、次にJavaは次の順序で実行します。

  1. オペランドが宣言された変数であることを確認します
  2. 左側のオペランドの値を保存します
  3. 右側のオペランドを評価する
  4. 複合演算子の指示に従って二項演算を実行します
  5. 二項演算の結果を左側の変数の型に変換します(暗黙のキャスト)
  6. 変換された結果を左側の変数に割り当てます

次に、左側のオペランドが配列の場合、実行する手順は少し異なります。

  1. 左側の配列式を確認し、正しくない場合はNullPointerExceptionまたはArrayIndexOutOfBoundsExceptionをスローします
  2. 配列要素をインデックスに保存します
  3. 右側のオペランドを評価する
  4. 選択した配列コンポーネントがプリミティブ型か参照型かを確認してから、左側のオペランドが変数であるかのように、最初のリストと同じ手順を続行します。

評価のいずれかのステップが失敗した場合、Javaは次のステップを実行し続けません。

配列要素に対するこれらの操作の評価に関連するいくつかの例を挙げましょう。

int[] numbers = null;

// Trying Incrementation
numbers[2] += 5;

予想どおり、これによりNullPointerExceptionがスローされます。

ただし、配列に初期値を割り当てると、次のようになります。

int[] numbers = {0, 1};

// Trying Incrementation
numbers[2] += 5;

NullPointerException、は削除されますが、使用されるインデックスが正しくないため、ArrayIndexOutOfBoundsExceptionが発生します。

これを修正すると、操作は正常に完了します。

int[] numbers = {0, 1};

// Incrementation
numbers[1] += 5; // x is now 6

最後に、 x 変数は、割り当ての最後で6になります。

5. 暗黙のキャスティング

複合演算子が役立つ理由の1つは、複合演算子が操作の方法を短くするだけでなく、暗黙的に変数をキャストすることです。

正式には、次の形式の複合代入式:

E1 op = E2

と同等です:

E1 –(T)(E1 op E2)

ここで、TE1のタイプです。

次の例を考えてみましょう。

long number = 10;
int i = number;
i = i * number; // Does not compile

最後の行がコンパイルされない理由を確認しましょう。

Javaは、操作で一緒になっている場合、小さいデータ型を大きいデータ型に自動的にプロモートしますが、は、大きいタイプから小さいデータ型に変換しようとするとエラーをスローします。

したがって、最初にilongにプロモートされ、次に乗算によって結果10Lが得られます。長い結果がi[に割り当てられます。 int であるX161X]は、エラーをスローします。

これは、明示的なキャストで修正できます。

i = (int) i * number;

この場合、Java複合代入演算子は、暗黙的なキャストを行うため、完璧です。

i *= number;

このステートメントは問題なく機能し、乗算結果を int にキャストし、値を左側の変数iに割り当てます。

6. 結論

この記事では、Javaの複合演算子を見て、いくつかの例とそれらのさまざまなタイプを示しました。 Javaがこれらの操作を評価する方法を説明しました。

最後に、暗黙のキャストについても確認しました。これは、これらの省略演算子が役立つ理由の1つです。

いつものように、この記事で言及されているすべてのコードスニペットは、GitHubリポジトリにあります。