Externalizable インターフェイスは java.io パッケージに以下のように定義されています。
public interface Externalizable extends Serializable {
public void writeExternal(ObjectOutput out) throws IOException;
public void readExternal(ObjectInput in) throws IOException,
ClassNotFoundException;
}
Serializable インターフェイスは直列化可能であることを示す印のようなものでしたが
Externalizable インターフェイスは実装するべきメソッドが定義されています。
Externalizable インターフェイスを実装したクラスには引数のないコンストラクタが必要です。
メソッドの実装に関してはコンパイラがチェックしてくれますがデフォルトコンストラクタが無い場合は実行時に以下のような例外が発生するので注意が必要です。
Exception in thread "main" java.io.InvalidClassException: SubBook; no valid constructor
at java.io.ObjectStreamClass.<init>(Unknown Source)
at java.io.ObjectStreamClass.lookup(Unknown Source)
at java.io.ObjectOutputStream.writeObject0(Unknown Source)
at java.io.ObjectOutputStream.writeObject(Unknown Source)
at BookSerializeSample.main(BookSerializeSample.java:13)
Externalizable オブジェクトの復元の際にはまず引数のないコンストラクタによりオブジェクトを生成してから readExternal メソッドを実行してフィールドの値を復元し、もし readResolve メソッドが定義されていれば readResolve メソッドを実行してその戻り値が最終的に復元されたオブジェクトとなります。 readResolve メソッドは直列化されるクラスに定義されている場合のみ実行され、スーパークラスの readResolve メソッドが実行されることは決してありません。
あるクラスが Externalizable インターフェイスを実装した以上はそのすべてのサブクラスにデフォルトコンストラクタを定義する必要があります(サブクラスで writeExternal や readExternal をオーバーライドしているかどうかは関係なく直列化の際に例外が発生する為)。 Externalizable インターフェイスを実装したクラスのサブクラスではスーパークラスで実装されている writeExternal や readExternal メソッドで正しく直列化、復元できない場合にはそれらのメソッドをオーバーライドする必要があります。
Externalizable インターフェイスを実装する場合には ObjectOutputStream による直列化の際にクラス情報は書き込まれますがそれ以外のバージョン管理などは writeExternal メソッドを実装するプログラマの責任となります( readExternal メソッドにおいても同様です )。 また writeExternal メソッドは public アクセスとなるので機密情報などを書き込む処理を実装している場合にはセキュリティ上好ましくないので暗号化して直列化するなどの処理が必要になるかもしれません。