この内容は古いバージョンです。最新バージョンを表示するには、戻るボタンを押してください。
バージョン:5
ページ更新者:guest
更新日時:2026-06-11 07:10:02

タイトル: 代入演算子
SEOタイトル: Java 代入演算子完全ガイド(=, +=, -=, *=, ビット演算複合, 連鎖代入)

この記事の要点
  • 基本代入 = は右辺の値を左辺に代入。右から左に評価
  • 複合代入 += -= *= /= %= &= |= ^= <<= >>= >>>=
  • 複合代入は暗黙のキャストを含む: b += 1.5b = (byte)(b + 1.5) 相当 (b が byte の場合)
  • 参照型参照のコピーString s1 = s2 は両者が同じオブジェクトを指す
  • 連鎖代入 a = b = ca = (b = c)。右結合

基本代入 =

右辺の値 (式の評価結果) を左辺の変数に格納する。代入式自体も値を持ち、左辺に代入された値が式の値となるため a = b = c のような連鎖が書けます。

int a = 10;
double d = 3.14;
String s = "hello";
boolean flag = true;

// 連鎖代入 (右結合)
int x, y, z;
x = y = z = 100;   // z=100 → y=100 → x=100

// 代入式は値を持つ
int n;
System.out.println(n = 5);   // 5 が出力され、n には 5 が代入される

複合代入演算子一覧

演算子等価式用途
+=a = a + b加算 / 文字列連結
-=a = a - b減算
*=a = a * b乗算
/=a = a / b除算 (整数同士なら切り捨て)
%=a = a % b剰余
&=a = a & bビット AND
|=a = a | bビット OR
^=a = a ^ bビット XOR
<<=a = a << b左シフト
>>=a = a >> b右シフト (符号維持)
>>>=a = a >>> b右シフト (符号無視 / 論理シフト)
int n = 10;
n += 5;    // n = 15
n -= 3;    // n = 12
n *= 2;    // n = 24
n /= 5;    // n = 4
n %= 3;    // n = 1

int flags = 0b1010;
flags |= 0b0100;   // 0b1110 (ビット ON)
flags &= 0b1100;   // 0b1100 (マスク)
flags ^= 0b0010;   // 0b1110 (反転)

// 文字列連結
String s = "Hello";
s += ", World";    // "Hello, World"

暗黙のキャスト (落とし穴)

複合代入 a += ba = (型)(a + b) 相当で、左辺の型に自動キャストされます。普通の a = a + b ではコンパイルエラーになるケースも、複合代入なら通ってしまうため注意:

byte b = 10;

// ❌ コンパイルエラー: b + 1 は int になる
// b = b + 1;
//     ^^^^^^ incompatible types: possible lossy conversion from int to byte

// ✅ 複合代入は暗黙キャストでコンパイル可
b += 1;   // = (byte)(b + 1)

// ⚠️ ただし精度落ちのバグに注意
byte x = 100;
x += 1.5;   // = (byte)(100 + 1.5) = (byte)101.5 = 101
            // 暗黙キャストで小数切り捨て

参照型の代入は参照コピー

プリミティブ (int / double / boolean 等) は値コピー、参照型 (オブジェクト / 配列) は参照のコピーです。

// プリミティブ: 値コピー
int a = 10;
int b = a;
b = 20;
System.out.println(a);   // 10 (a は変わらない)

// 参照型: 参照コピー
int[] arr1 = {1, 2, 3};
int[] arr2 = arr1;       // 同じ配列を指す
arr2[0] = 99;
System.out.println(arr1[0]);   // 99 (arr1 も変わる!)

// 独立したコピーが欲しいなら明示的に
int[] arr3 = arr1.clone();
arr3[0] = 0;
System.out.println(arr1[0]);   // 99 (arr3 は別物)

// String は immutable なので参照コピーでも事故りにくい
String s1 = "hello";
String s2 = s1;
s2 = "world";   // s1 は "hello" のまま (再代入は別オブジェクトを指すだけ)

AutoBoxing と代入

プリミティブとそのラッパー型 (Integer / Double 等) の間は自動変換 (AutoBoxing / UnBoxing) が働きます。

Integer boxed = 10;     // AutoBoxing: int → Integer.valueOf(10)
int primitive = boxed;  // UnBoxing: boxed.intValue()

// null をプリミティブに UnBox すると NullPointerException
Integer maybe = null;
int n = maybe;   // ❌ NullPointerException

// コレクション要素への代入
List<Integer> list = new ArrayList<>();
list.add(1);     // AutoBoxing
list.add(2);
int sum = 0;
for (int v : list) sum += v;   // UnBoxing

配列要素 / フィールドへの代入

int[] arr = new int[5];
arr[0] = 100;           // 配列要素代入
arr[arr.length - 1] = 999;

User u = new User();
u.name = "Taro";        // フィールド代入 (public の場合)
u.setName("Taro");      // setter 経由 (推奨)

// インデックス計算式も使える
int i = 2;
arr[i + 1] = 50;

他言語との比較

演算子JavaPHPJavaScriptPython
=OKOKOKOK
+= 他算術系OKOKOKOK
??= (null 合体代入)×OK (7.4+)OK (ES2021+)×
||= / &&=××OK (ES2021+)×
連鎖代入 a = b = cOKOKOKOK

評価順序: 右から左

int a = 1, b = 2, c = 3;

// 代入は右結合 → a = (b = (c = 5))
a = b = c = 5;
// 評価順: c = 5 → b = 5 → a = 5
// 結果: a = b = c = 5

// 副作用がある場合は要注意
int[] arr = {0, 0, 0};
int i = 0;
arr[i++] = i++;
// 左辺で arr[0] を確保し i=1、右辺で i=1 を代入し i=2
// arr = {1, 0, 0}, i = 2

FAQ

Q: i++++i はどちらが速い?
A: プリミティブに対しては JIT 最適化されるためほぼ差なし。意味が違うので結果から選ぶこと。

Q: String s += "x" をループで使うと遅い?
A: はい。毎回新しい String が生成されます。ループ内では StringBuilder.append() を使う。

Q: final 変数に複合代入はできる?
A: できません。final は一度代入したら再代入禁止なので、final int n = 0; n += 1; はコンパイルエラー。