シリアライズ(Serializable の注意点) — 永続化 / 送受信
Javaの シリアライズ は「オブジェクトをバイト列に変換して保存や送受信できるようにする」仕組みです。
ファイル保存、ネットワーク送信、キャッシュなどで使われますが、初心者がつまずきやすい注意点も多いので、かみ砕いて解説します。
基本の仕組み
- Serializable インターフェース:
マーカーインターフェース(メソッドなし)。これを実装すると、そのクラスはシリアライズ可能になる。 - ObjectOutputStream / ObjectInputStream:
ファイルやストリームにオブジェクトを書き出し/読み込みするクラス。
import java.io.*;
class User implements Serializable {
private String name;
private int age;
public User(String name, int age) { this.name = name; this.age = age; }
public String toString() { return name + "(" + age + ")"; }
}
public class SerializeDemo {
public static void main(String[] args) throws Exception {
User u = new User("Tanaka", 20);
// 保存
try (ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("user.ser"))) {
out.writeObject(u);
}
// 復元
try (ObjectInputStream in = new ObjectInputStream(new FileInputStream("user.ser"))) {
User restored = (User) in.readObject();
System.out.println(restored); // Tanaka(20)
}
}
}
Java注意点(初心者が知っておくべき)
- serialVersionUID を明示する
- クラスのバージョン識別子。自動生成に頼ると、フィールド変更で互換性エラーが出る。
- 明示的に定義しておくのが安全。
private static final long serialVersionUID = 1L;
Java- transient フィールドは保存されない
- パスワードや一時キャッシュなど「保存したくない」フィールドは
transientを付ける。 - 復元時はデフォルト値(null/0/false)になる。
- パスワードや一時キャッシュなど「保存したくない」フィールドは
private transient String password;
Java- 親クラスが Serializable でない場合
- 親が Serializable を実装していないと、そのフィールドはシリアライズされない。
- 必要なら
writeObject/readObjectをオーバーライドして手動で処理。
- 互換性の問題
- フィールドを追加・削除すると、古いバージョンのデータが読み込めなくなることがある。
- 長期保存用途には JSON や XML の方が安全。
- セキュリティリスク
- 外部から送られてきたシリアライズデータをそのまま復元すると、任意コード実行の危険がある。
- 信頼できるデータだけを扱うこと。
例題で練習
例題1: transient の効果
class Account implements Serializable {
private String user;
private transient String password; // 保存しない
public Account(String user, String password) {
this.user = user; this.password = password;
}
public String toString() { return user + ":" + password; }
}
Java- 保存後に復元すると
passwordはnullになる。
👉 「保存したくない情報」を守れる。
例題2: serialVersionUID の互換性
class Config implements Serializable {
private static final long serialVersionUID = 1L;
private int version;
}
Java- 将来フィールドを追加しても、
serialVersionUIDが同じなら古いデータを読み込める。
👉 バージョン管理のために必ず定義する。
例題3: ネットワーク送受信
// サーバ側
ObjectOutputStream out = new ObjectOutputStream(socket.getOutputStream());
out.writeObject(new User("Sato", 30));
// クライアント側
ObjectInputStream in = new ObjectInputStream(socket.getInputStream());
User u = (User) in.readObject();
System.out.println(u);
Java👉 ファイル保存と同じ仕組みで、ネットワーク送信も可能。
テンプレート集
Serializable クラス
class MyClass implements Serializable {
private static final long serialVersionUID = 1L;
private 型 フィールド;
private transient 型 一時フィールド;
}
Java保存
try (ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("file.ser"))) {
out.writeObject(obj);
}
Java復元
try (ObjectInputStream in = new ObjectInputStream(new FileInputStream("file.ser"))) {
MyClass obj = (MyClass) in.readObject();
}
Javaまとめ
- Serializable は「オブジェクトをバイト列に変換」する仕組み。
- 注意点:
serialVersionUIDを明示、transientで不要データを除外、互換性とセキュリティに注意。 - 用途: 永続化(ファイル保存)、送受信(ソケット通信)、キャッシュ。
- 長期保存や外部連携: JSON/XML の方が安全で柔軟。
👉 練習課題として「ユーザークラス」を作り、パスワードを transient にして保存・復元すると、シリアライズの仕組みと注意点が体感できます。
