通常同じ VM 上で直列化と復元を行った場合でも復元時には直列化時のオブジェクトとは別の新たなオブジェクトが作成されます。 しかし復元後でも共有していたオブジェクトの一意性は保たれています。 つまり同じオブジェクトの参照を持つ複数の変数が存在する場合には復元後にもそれらの変数は復元時に作成された同一のオブジェクトの参照を保持します。
例えば java.util.HashMap クラスは Serializable インターフェイスを実装してますがその HashMap に一つの Book オブジェクトを2つのキーを使って格納して直列化します。 そして HashMap を復元してから直列化時の HashMap と参照先を比べてみます。 これは復元時に新たに HashMap が作成されるので別々の参照になるはずです。 また直列化時に作成した Book オブジェクトと復元後の HashMap から取り出した Book オブジェクトの参照を比べるとやはり復元時に新たに Book オブジェクトが作成されるので別々の参照を保持しているはずです。 しかし復元後の HashMap から別々のキーで取り出した2つの Book オブジェクトは復元時に作成された同じ Book オブジェクトを参照しているはずです。 これらの振る舞いのテストを BookSerializeSample で行いました。 BookSerializeSample の実行結果は以下のようになります。
(map == books) -> false
(book == book1) -> false
(book1 == book2) -> true
book1 -> Book title:きまぐれロボット author:星新一
book2.setTitle("ボッコちゃん");
book1 -> Book title:ボッコちゃん author:星新一
また Serializable オブジェクト A と B がある場合に A は B
の参照をフィールドとして保持し、B は A の参照をフィールドとして保持しているような場合でも参照関係は正しく直列化、復元されます。
/********************* BookSerializeSample.java *********************/
import java.io.*;
import java.util.HashMap;
public class BookSerializeSample {
public static void main(String[] args) throws Exception {
HashMap map = new HashMap();
Book book = new Book("きまぐれロボット", "星新一");
map.put("book1", book);
map.put("book2", book);
ObjectOutputStream out = null;
ObjectInputStream in = null;
try {
out = new ObjectOutputStream(
new BufferedOutputStream(
new FileOutputStream("books")));
out.writeObject(map);
out.close();
out = null;
in = new ObjectInputStream(
new BufferedInputStream(
new FileInputStream("books")));
HashMap books = (HashMap)in.readObject();
Book book1 = (Book)books.get("book1");
Book book2 = (Book)books.get("book2");
System.out.println("(map == books) -> " + (map == books));
System.out.println("(book == book1) -> " + (book == book1));
System.out.println("(book1 == book2) -> " + (book1 == book2));
System.out.println("book1 -> " + book1);
book2.setTitle("ボッコちゃん");
System.out.println("book2.setTitle(\"ボッコちゃん\");");
System.out.println("book1 -> " + book1);
} finally {
if (out != null) {
try {
out.close();
} catch (IOException e) {
//プログラムは終了するのでこの例外が万一発生しても無視します。
//この例外をスローしてしまうと ObjectOutputStream#writeObject や
//ObjectInputStream#readObject で例外が発生していた場合に
//それらの例外がスローされなくなってしまうので catch しています。
}
}
if (in != null) {
try {
in.close();
} catch (IOException e) {}
}
}
}
}
/**************************** Book.java ****************************/
public class Book implements java.io.Serializable {
protected String title;
protected String author;
public 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;
}
}