たとえば、FooとBarという2つのクラスがあり、BarがFooを拡張してSerializable
を実装しているとします。
class Foo {
public String name;
public Foo() {
this.name = "Default";
}
public Foo(String name) {
this.name = name;
}
}
class Bar extends Foo implements Java.io.Serializable {
public int id;
public Bar(String name, int id) {
super(name);
this.id = id;
}
}
FooはSerializable
を実装していないことに注意してください。では、バーがシリアル化されるとどうなりますか?
public static void main(String[] args) throws Exception {
FileOutputStream fStream=new FileOutputStream("objects.dat");
ObjectOutputStream oStream=new ObjectOutputStream(fStream);
Bar bar=new Bar("myName",21);
oStream.writeObject(bar);
FileInputStream ifstream = new FileInputStream("objects.dat");
ObjectInputStream istream = new ObjectInputStream(ifstream);
Bar bar1 = (Bar) istream.readObject();
System.out.println(bar1.name + " " + bar1.id);
}
「デフォルト21」を出力します。問題は、クラスがシリアル化されていないときにデフォルトのコンストラクターが呼び出されるのはなぜですか?
Serializableは、特定のクラスの単なる「マーカーインターフェイス」です。
ただし、そのクラスは特定の規則に従う必要があります。
http://docs.Oracle.com/javase/1.5.0/docs/api/Java/io/Serializable.html
非直列化可能クラスのサブタイプを直列化できるようにするために、サブタイプは、スーパータイプのパブリック、保護、および(アクセス可能な場合)パッケージフィールドの状態を保存および復元する責任を負います。サブタイプがこの責任を負うのは、それが拡張するクラスに、クラスの状態を初期化するためのアクセス可能な引数なしのコンストラクターがある場合のみです。そうでない場合、Serializableクラスを宣言するとエラーになります。
@Sleiman Jneidiの質問に回答するために、上記のOracleドキュメントで明確に述べられている
逆シリアル化中に、シリアル化できないクラスのフィールドは、クラスのパブリックまたは保護された引数なしのコンストラクターを使用して初期化されます。引数なしのコンストラクターは、シリアル化可能なサブクラスからアクセスできる必要があります。直列化可能なサブクラスのフィールドは、ストリームから復元されます。
したがって、Fooクラスのデフォルトの引数なしコンストラクターが呼び出され、初期化されました。
defaultWriteObjectは、現在のクラス の非静的フィールドおよび非一時フィールドのみを書き込むことができる可能性があります。スーパークラスがSerializableインターフェースを実装しないと、スーパークラスのフィールドをストリームに直列化できません。
実際には、シリアライズされていないため、親クラスのオブジェクトを読み戻すと、シリアライズされないため、JVMは、新しいキーワードを使用して新しいオブジェクトを作成するときに使用するのと同じプロセスを繰り返します。