演算子の優先順位

足し算よりかけ算の方が優先順位が高いことは、算数を学習して以来の常識と言っていいでしょう。 また、1-2+3のように、同じ優先順位の演算子が使われている場合は、左の方から計算していくこともご存知ですね。 それでは、javaの演算子にはどのような規則が有るのでしょうか。

演算子の優先順位

Javaには多くの演算子があり、優先順位が厳格に定められています。

表 5-3 : 演算子の優先順位
優先順位 演算子 名前 結合規則
1 () 引数
[] 配列アクセス
. メンバアクセス
++ 後置インクリメント
-- 後置デクリメント
2 ! 論理否定
~ 補数
+ プラス
- マイナス
++ 前置インクリメント
-- 前置デクリメント
3 new オブジェクト生成
() キャスト
4 * 乗算
/ 除算
% 剰余
5 + 加算
- 減算
6 << 左シフト
>> 右シフト
>>> 符号なし右シフト
7 > より大きい
>= 以上
< より小さい
<= 以下
instanceof 型比較
8 == 等価
!= 非等価
9 & ビット論理積
10 ^ ビット排他的論理和
11 | ビット論理和
12 && 論理積
13 || 論理和
14 ?: 条件
15 = 代入
+= 加算代入
-= 減算代入
*= 乗算代入
/= 除算代入
%= 剰余代入
&= 論理積代入
|= 論理和代入
^= 排他的論理和代入
<<= 左シフト代入
>>= 右シフト代入
>>>= 符号なし右シフト代入

例えば、

a = 3 + 2 * 4

という式を考えてみましょう。優先順位は * , + , = の順になります。したがって、2 * 4が先に計算され、次に3+8が計算されます。そして、最後に11がaに代入されるのです。

3 + 2の方を先に計算させたい場合は、

a = ( 3 + 2 ) * 4

のように()を使います。

結合規則

では、次のように、同じ優先順位の演算子がいくつか使われている場合はどうなるのでしょうか。

a = 5 - 2 + 1

- と + の優先順位が同じですが、結合規則が「左」なので、左の方から順番に評価されます。つまり、

a = (5 - 2) + 1

という式と同じことになります。したがって、5-2が先に計算され、次に3+1が計算されます。そして、最後に4がaに代入されるのです。

もう一つの例を見てみましょう。

a = b =1;

= が2つもあるので驚かれたかもしれませんが、慌てることはありません。この式の演算子は2つの = です。 = と = は優先順位が同じですが、結合規則は「右」なので、右の方から評価されます。つまり、

a = ( b =1 );

という式と同じことになります。したがって、まずbに1が代入されます。 b = 1 という式を評価した値は代入された後のbの値そのもの、即ち1です。したがって、最後にaに1が代入されることになります。

では、OperatorSample01.javaのコードを少し変更して、ちょっとした実験をしてみましょう。

OperatorSample01.java(再掲)
class OperatorSample01 {
    public static void main(String[] args){
        int a = 8;
        int b = 2;
        
        System.out.println("a + b = " + ( a + b ) );
        System.out.println("a - b = " + ( a - b ) );
        System.out.println("a * b = " + ( a * b ) );
        System.out.println("a / b = " + ( a / b ) );
        System.out.println("a % b = " + ( a % b ) );
    }
}
OperatorSample01の実行結果(再掲)
a + b = 10
a - b = 6
a * b = 16
a / b = 4
a % b = 0

変更後のコードは、次のOperatorSample01A.javaです。

OperatorSample01A.java
class OperatorSample01A {
    public static void main(String[] args){
        int a = 8;
        int b = 2;
        
        System.out.println("a + b = " +  a + b  );
        //System.out.println("a - b = " +  a - b  );
        System.out.println("a * b = " +  a * b  );
        System.out.println("a / b = " +  a / b  );
        System.out.println("a % b = " +  a % b  );
    }
}

OperatorSample01.javaの

        System.out.println("a + b = " + ( a + b ) );

の部分で、( a + b )の()を外して、

        System.out.println("a + b = " + a + b );

のように変更してみました。同様に、乗算、除算、剰余についても、()を外してみました。ただし、減算だけはコメントアウトしておきます。

OperatorSample01Aの実行結果
a + b = 82
a * b = 16
a / b = 4
a % b = 0

コンパイルして実行すると、加算の出力だけがおかしなことになっていますね。なぜでしょうか。そう、

a + b

という部分よりも

"a + b = " + a

の方が先に評価されてしまうからです。加算は左結合です。演算子が加算だけで、()が無ければ、左の方から順番に評価されることを思い出してください。
減算だけコメントアウトした理由もお分かりでしょうか。文字列から整数を引くことはできないので、エラーが出て、コンパイルができないからです。
乗算、除算、剰余は、もともと加算より優先順位が高いので、()をはずしても影響はありません。

式を書くときは、演算子の優先順位と結合規則に注意