📝
【Java Gold】シリアライズ・デシリアライズについて
JavaのreadObject
・writeObject
・readResolve
・writeReplace
を整理するために書きました。
シリアライズ・デシリアライズとは
Javaでは、オブジェクトをファイルなどに保存したり、復元したりするために、シリアライズ/デシリアライズという仕組みが用意されています。
- シリアライズ(Serialize):オブジェクトの状態をバイト列に変換して保存すること
- デシリアライズ(Deserialize):保存されたバイト列からオブジェクトを復元すること
Serializableインタフェースの実装が必要
シリアライズ対象のクラスは、java.io.Serializable
インタフェースを実装する必要があります。
このインタフェースはマーカーインタフェースであり、特定のメソッドを持ちません。
import java.io.Serializable;
public class User implements Serializable {
private String name;
private int age;
}
readObject / writeObject とは
Javaは、標準で自動的にシリアライズ/デシリアライズ処理を行いますが、動作をカスタマイズしたい場合は、以下のメソッドを定義することができます。
writeObject
private void writeObject(ObjectOutputStream out) throws IOException
- オブジェクトのシリアライズ時に呼ばれます。
-
out.defaultWriteObject()
によりデフォルトの書き出しを行い、必要に応じて追加の処理が可能です。
readObject
private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException
- デシリアライズ直後に呼ばれます。
-
in.defaultReadObject()
により標準の復元を行い、追加の処理を行うことができます。
使用例
import java.io.*;
class User implements Serializable {
private String name;
private int age;
private void writeObject(ObjectOutputStream out) throws IOException {
out.defaultWriteObject();
// 必要な追加処理
}
private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
in.defaultReadObject();
// 復元後の処理
}
}
補足
- 両メソッドとも private で定義する必要があります。
- 一時的なフィールドは
transient
修飾子を付けることで、シリアライズ対象外にできます。
シリアライズ/デシリアライズの基本的な使用例
// シリアライズ
ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("user.ser"));
out.writeObject(user); // userはSerializableを実装したオブジェクト
out.close();
// デシリアライズ
ObjectInputStream in = new ObjectInputStream(new FileInputStream("user.ser"));
User user2 = (User) in.readObject();
in.close();
writeReplace / readResolve とは
オブジェクトのシリアライズ/デシリアライズ時に、別のオブジェクトへ置き換えるための仕組みです。
writeReplace
private Object writeReplace() throws ObjectStreamException
- シリアライズの直前に呼ばれます。
- 戻り値のオブジェクトが、実際にシリアライズされます。
使用例
private Object writeReplace() throws ObjectStreamException {
return new ProxyUser(name); // ProxyUserは別クラス
}
readResolve
private Object readResolve() throws ObjectStreamException
- デシリアライズ直後に呼ばれ、戻り値のオブジェクトが返されます。
- Singletonパターンなどで使用されます。
使用例
private Object readResolve() throws ObjectStreamException {
return Singleton.getInstance();
}
補足
- どちらも private で定義します。
-
ObjectStreamException
をスロー可能にするのが推奨されます(明示的で安全です)。 - これらのメソッドは、標準のシリアライズ処理には不要で、特殊な用途(不変性保持、Singleton実装、セキュリティ目的など)で利用されます。
まとめ
メソッド名 | タイミング | 目的 |
---|---|---|
writeObject |
シリアライズ時 | デフォルト処理+独自の書き出し処理 |
readObject |
デシリアライズ時 | デフォルト復元+復元後の独自処理 |
writeReplace |
シリアライズ時 | 別オブジェクトに置き換えて書き出し |
readResolve |
デシリアライズ時 | 復元されたオブジェクトを別のものに差し替える |
おわりに
誤記や改善点があればコメントなどでご指摘ください。
Discussion