Java | 基礎文法:代入演算子

Java Java
スポンサーリンク

代入演算子の全体像

代入演算子は「右側の式を評価して、その結果を左側の変数に入れる」ための基本ツールです。最も基本は =(代入)で、派生として「加算して代入」の += や「乗算して代入」の *= などの複合代入演算子があります。代入は式でもあり、値を返します(右側の値と同じ)。そのため a = b = 10; のようなチェーンも可能ですが、可読性の観点で乱用は避けましょう。


基本の = と評価順序・チェーン

代入の評価順序と式としての代入

代入は右→左の順で評価されます。まず右側の式を完全に計算し、その結果を左の変数へ格納します。代入式自体はその結果値(右側の値)を返すため、連鎖代入や条件式内での代入が可能です。

int a, b;
a = b = 10;          // まず b に 10、次に a に 10。式の値は 10
int x = (a = 5) + 2; // a に 5 を入れてから、式は 7 を返す
Java

条件式の中での代入(例: if ((x = f()) > 0) ...)は動作しますが、副作用で読み手を混乱させやすいので、初心者は「代入は代入だけ」に分けるのを推奨します。


複合代入の使い方と挙動

よく使う複合代入(算術)

x += yx = x + y の短縮形で、-=*=/=, %= も同様です。読みやすさと一貫性が上がるため、累積・更新では積極的に使います。

int n = 10;
n += 3;   // 13
n -= 2;   // 11
n *= 4;   // 44
n /= 5;   // 8(整数割り算:小数切り捨て)
n %= 3;   // 2(余り)
Java

ビット演算の複合代入

ビットフラグの更新には &=, |=, ^=, <<=, >>=, >>>= が使えます。権限や状態フラグの管理で活躍します。

int READ = 0b0001, WRITE = 0b0010, EXEC = 0b0100;

int perm = READ;
perm |= WRITE;   // WRITE を付与(OR)
perm &= ~READ;   // READ を外す(AND と NOT)
perm ^= EXEC;    // EXEC をトグル(XOR)
Java

文字列の +=(連結)

String は不変ですが、+= は「新しい文字列を作って再代入」します。ループでの多用は非効率なので、繰り返し連結は StringBuilder を使うのが定石です。

String s = "Java";
s += " Basics"; // "Java Basics"(新しいインスタンスに置き換わる)
Java

型とキャストの落とし穴(重要ポイントの深掘り)

short/byte の複合代入だけ通る理由

shortbyte に対して s = s + 1; はコンパイルエラーになります(計算結果が int になるため)。一方で s += 1; は暗黙キャスト込みで許可されます。この仕様差は初心者がよくつまずくポイントです。

short s = 1;
// s = s + 1;   // NG(int を short に暗黙変換できない)
s += 1;          // OK(複合代入は暗黙にキャストされる)
Java

この挙動に頼ると型の境界が曖昧になるため、明示的キャストか、最初から int を使う方が安全です。

オーバーフローは例外にならない

整数の加算・乗算は範囲を超えても例外にならず、値が循環します。複合代入でも同じです。大きく増減する可能性があるなら、型を long に上げる、または境界チェックを入れましょう。

int x = Integer.MAX_VALUE;
x += 1; // -2147483648(循環)
Java

参照型への代入とミューテーションの誤解(重要ポイントの深掘り)

「参照を代入する」ことの意味

参照型(配列、List、独自クラスなど)では、代入は「参照のコピー」です。代入後、同じオブジェクトを別名で指すことになり、片方からの変更がもう片方にも見えます。

int[] a = {1, 2};
int[] b = a;    // 同じ配列参照を共有
b[0] = 99;
System.out.println(a[0]); // 99(a からも変更が見える)
Java

「独立したコピー」が欲しいなら、明示的に複製(clone、コンストラクタコピー、ユーティリティ)を作る必要があります。String は不変なのでこの共有による書き換えは起きません。


final と再代入禁止、スコープ(設計視点の深掘り)

final は「参照の再代入」を止める

final 変数は「一度だけ代入可能」で、以降の再代入を禁止します。参照型の final は「参照の入れ替えが禁止」であり、オブジェクト内部の変更まで禁止するわけではありません(不変にしたいなら不変クラスで設計)。

final List<String> list = new java.util.ArrayList<>();
list.add("A");     // OK(中身の変更)
/* list = new ArrayList<>(); */ // NG(再代入)
Java

スコープ内で最小限に宣言する

代入はスコープごとに考えると安全です。必要な箇所に最短のスコープで宣言・初期化し、不要な再代入を避けると、意図が明確でバグの温床が減ります。


実用例で身につける

例 1: 累積計算(複合代入の基本)

public class Accumulate {
    public static void main(String[] args) {
        int sum = 0;
        for (int i = 1; i <= 5; i++) {
            sum += i; // 累積
        }
        System.out.println(sum); // 15
    }
}
Java

+= は「読む・書く」が一体化していて、累積ロジックを簡潔に保てます。

例 2: ペナルティと下限ゼロ(安全な更新)

public class Penalty {
    public static void main(String[] args) {
        int points = 10;
        points -= 12;                 // -2
        points = Math.max(points, 0); // 下限ゼロへ正規化
        System.out.println(points);   // 0
    }
}
Java

更新後に境界を正規化するパターンは、在庫・スコア・残高などで有効です。

例 3: フラグの付与・除去・トグル(ビット複合代入)

public class Flags {
    public static void main(String[] args) {
        int READ = 1, WRITE = 2, EXEC = 4;
        int perm = 0;

        perm |= READ;   // 付与
        perm |= WRITE;  // 付与
        perm &= ~READ;  // 除去
        perm ^= EXEC;   // トグル

        System.out.println(perm); // 状態を数値で表現
    }
}
Java

ビット複合代入は「意図が見える」更新で、権限や状態の管理に向いています。


仕上げのアドバイス(重要ポイントのまとめ)

  • 代入は「右を評価して左に入れる」。式として値を返すが、読みやすさを最優先して副作用の混在は避ける。
  • 複合代入は短く明快。short/byte の暗黙キャストに頼りすぎず、型を揃えるか明示キャストで安全に。
  • 参照型の代入は「同じオブジェクトを共有」。独立性が必要ならコピーを作る。
  • オーバーフローは沈黙する。範囲を見積もり、必要なら long や正規化で守る。
  • 変更不要なものは final にして再代入を禁止。スコープは最小、更新は意図が伝わる形で。

タイトルとURLをコピーしました