下の SubBook クラスは Serializable インターフェイスを実装していますがそのスーパークラスの Book クラスは Serializable インターフェイスを実装してません。 その為デフォルトでは SubBook オブジェクトを直列化、復元すると Book クラスで定義しているフィールド title author の値は失われます。 これに対処する為に SubBook クラスには readObject writeObject を実装しています。
readObject writeObject メソッドは Java の直列化フレームワークにおいて Serializable を実装しているクラスが定義している場合のみ意味のあるメソッドであり、インターフェイスやどこかのクラスに定義されているメソッドをオーバーライドしているわけではありません。また Externalizable を実装しているクラスがこれらのメソッドを定義しても直列化(永続化)の際に呼び出されることありません。
例えば Serializable インターフェイスを実装しているクラスのインスタンス A を ObjectOutputStreame#writeObject で直列化する際には A に writeObject メソッドが定義されていればその writeObject メソッドを呼び出し、そうでなければ ObjectOutputStreame の defaultWriteObject が使用されます。 復元時には A に readObject メソッドが定義されていればその readObject メソッドを呼び出し、そうでなければ ObjectInputStreame の defaultReadObject が使用されます。
Object -> U -> S -> Foo上の継承関係で U, S, Foo クラスのクラス宣言は
public class U public class S extends U implements java.io.Serializable public class Foo extends Sとなっているとします。
writeObject readObject メソッドは正確に以下の用に定義しなければなりません。 ( out や in という引数名は任意です)
private void writeObject(ObjectOutputStream out) throws IOException private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException
SubBook#writeObject ではまず引数の ObjectOutputStream オブジェクトの defaultWriteObject メソッドを呼び出して writeObject メソッドを定義していない場合と同じ処理を行います。 その上で付加するべき処理であるスーパークラスの title author の両フィールドを ストリームに書き込んで直列化しています。 SubBook#readObject では writeObject メソッドと同様に ObjectInputStream#defaultReadObject メソッドでデフォルトの処理を行った上で writeObject メソッドで書き込んだ title author の順に読み込みを行っています。 BookSerializeSample の実行結果は以下です。
SubBook title:きまぐれロボット author:星新一 price:357
/**************************** Book.java ****************************/
public class Book {
protected String title;
protected String author;
protected Book() {}
public Book(String title, String author) {
this.title = title;
this.author = author;
}
//--------------------------------------------------------------------
public String getAuthor() {
return author;
}
public void setAuthor(String author) {
this.author = author;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
//--------------------------------------------------------------------
public String toString() {
return "Book title:" + title + " author:" + author;
}
}
/**************************** SubBook.java ****************************/
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.io.IOException;
import java.io.ObjectInputStream;
public class SubBook extends Book implements Serializable {
protected int price;
public SubBook(String title, String author, int price) {
super(title, author);
this.price = price;
}
//--------------------------------------------------------------------
public int getPrice() {
return price;
}
public void setPrice(int price) {
this.price = price;
}
//--------------------------------------------------------------------
private void writeObject(ObjectOutputStream out) throws IOException {
out.defaultWriteObject();
out.writeObject(title);
out.writeObject(author);
}
private void readObject(ObjectInputStream in)
throws IOException, ClassNotFoundException {
in.defaultReadObject();
title = (String)in.readObject();
author = (String)in.readObject();
}
//--------------------------------------------------------------------
public String toString() {
return "SubBook title:" + title + " author:" + author +
" price:" + price;
}
}
/********************* BookSerializeSample.java *********************/
import java.io.*;
public class BookSerializeSample {
public static void main(String[] args) throws Exception {
SubBook book = new SubBook("きまぐれロボット", "星新一", 357);
ObjectOutputStream out = null;
ObjectInputStream in = null;
try {
out = new ObjectOutputStream(new BufferedOutputStream(
new FileOutputStream("data")));
out.writeObject(book);
out.close();
out = null;
in = new ObjectInputStream(new BufferedInputStream(
new FileInputStream("data")));
System.out.println(in.readObject());
} finally {
if (out != null) {
try {
out.close();
} catch (IOException e) {}
}
if (in != null) {
try {
in.close();
} catch (IOException e) {}
}
}
}
}