マイナー・マイナー

隠れた名作の発掘が生きがい。

サブクラスを直列化する際に,直列化可能でないスーパークラスで注意すること


スポンサードリンク

スーパークラスが直列化可能でなく,サブクラスが直列化可能である場合,サブクラスのオブジェクトの入出力を行うときには引数のないコンストラクタが呼ばれるそうです.また,スーパークラスが直列化可能な場合,サブクラスも直列化可能であるため,コンストラクタは指定したものが使われます.


これを確かめるプログラムの具体例を以下に記述します.AはBのスーパークラス,BはCのスーパークラスです.

import java.io.*;

class A {
	String a;

	public A(String a) {
		this.a = a;
		System.out.println("A1");
	}

	public A() {
		this.a = "A2";
		System.out.println("A2");
	}
}

class B extends A implements Serializable {
	String b;

	public B(String a, String b) {
		super(a);
		this.b = b;
		System.out.println("B1");
	}

	public B() {
		this.b = "B2";
		System.out.println("B2");
	}
}

class C extends B {
	String c;

	public C(String a, String b, String c) {
		super(a, b);
		this.c = c;
		System.out.println("C2");
	}

	public C() {
		this.c = "C2";
		System.out.println("C2");
	}

	public void show() {
		System.out.println("(a, b, c) = (" + a + ", " + b + ", " + c + ")");
	}
}

public class SerializeTest {

	public static void main(String[] args) {

		String path = args[0];

		File file = new File(path);

		try {
			System.out.println("Write");
			ObjectOutputStream oos = new ObjectOutputStream(
					new FileOutputStream(file));

			C cOut = new C("A1", "B1", "C1");
			oos.writeObject(cOut);
			oos.flush();
			oos.close();
			cOut.show();

			System.out.println();

			System.out.println("Read");
			ObjectInputStream ois = new ObjectInputStream(new FileInputStream(
					file));
			C cIn = (C) ois.readObject();
			ois.close();
			cIn.show();

		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		}
	}
}


実行結果


Write
A1
B1
C2
(a, b, c) = (A1, B1, C1)

Read
A2
(a, b, c) = (A2, B1, C1)


Cのコンストラクタを呼び出すと,A,B,Cの引数ありのコンストラクタが順番に呼び出されます.これを一度ファイルに出力し,再度読み込むとAの引数なしのコンストラクタが呼び出されます.これは,Aが直列化可能ではなく,変数aの値は保持されないために生じる現象です.そのため,サブクラスで直列化を行う際にはスーパークラスで引数なしのコンストラクタを定義することを考慮しなければならないようです.