📝

【Java Gold】シリアライズ・デシリアライズについて

に公開

JavaのreadObjectwriteObjectreadResolvewriteReplaceを整理するために書きました。


シリアライズ・デシリアライズとは

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