一般的にクラスのバージョン(構造)が異なる場合デシリアライズできませんが、以下の様なことをしておくとシリアライズ、デシリアライズが可能です。
- private static final long serialVersionUIDを定義
- writeObject/readObjectを実装する。
serialVersionUIDは知っていましたが、writeObject/readObjectは知らなかった。
writeObject/readObjectは特にSerializableインターフェース等に定義されているわけではないが、Serializableインターフェースをインプリメントすると使用されることになるちょっと不思議なメソッド。
writeObject メソッドが定義されていればその writeObject メソッドを呼び出し、そうでなければ ObjectOutputStreame の defaultWriteObject が使用されるらしい。
public class Rectangle extends Figure implements Serializable { public Rectangle(int x, int y, int width, int height) { setValues(x, y); width_ = width; height_ = height; } private void writeObject(ObjectOutputStream out) throws IOException { out.defaultWriteObject(); // Rectangleをシリアライズ out.writeInt(getX()); // Figureのデータをシリアライズ out.writeInt(getY()); // } private void readObject(ObjectInputStream in) thows IOException, ClassNotFoundException { in.defaultReadObject(); // Figureは引数なしコンストラクタで初期化 // Rectangleをデシリアライズ(復元) int x = in.readInt(); // Figureのデータをデシリアライズ(復元) int y = in.readInt(); // setValues(x, y); // Figureに復元したデータを設定 } private int width_; private int height_; }http://www.asahi-net.or.jp/~DP8T-ASM/java/tips/Serializable.html
そして、バージョンの異なる(定義の異なる)クラスをシリアライズ・デシリアライズした場合
フィールドの値は以下のようになります。
元にある | 元にない | |
先にある | 値が引き継がれる | Null |
先にない | 無視 | 無視 |
NULLになるところの場合変数宣言時に初期化をしていてもNULLもしくは0になります。
プリミティブなものは初期値(intなら0)になります。
普段何気なく使っているものをどれだけ知らないか、改めて認識。