HHeLiBeXの日記 正道編

日々の記憶の記録とメモ‥

シリアライズの罠 - java.lang.Boolean

つい最近まで、Booleanオブジェクトはデシリアライズされる際に新たなオブジェクトが生成されない(より厳密に言うと、生成された直後にGC可能オブジェクトになる)と思い込んでいた、という罠。
確認のためのコード。

import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectInputStream;
import java.io.ObjectOutput;
import java.io.ObjectOutputStream;
import java.io.PipedInputStream;
import java.io.PipedOutputStream;

public class Main {

    public static void main(String[] args) throws IOException, ClassNotFoundException {
        System.out.println("java.version:   " + System.getProperty("java.version"));
        System.out.println("java.vm.vendor: " + System.getProperty("java.vm.vendor"));
        System.out.println();

        PipedInputStream pin = new PipedInputStream();
        PipedOutputStream pout = new PipedOutputStream(pin);
        ObjectOutput out = new ObjectOutputStream(pout);
        ObjectInput in = new ObjectInputStream(pin);

        test("Boolean.TRUE", Boolean.TRUE, out, in);
        test("Boolean.FALSE", Boolean.FALSE, out, in);
        test("new Boolean(false)", new Boolean(false), out, in);
    }

    private static void test(String label, Boolean obj, ObjectOutput out, ObjectInput in) throws IOException, ClassNotFoundException {
        System.out.printf("%24s:sender:   %s\n", label, System.identityHashCode(obj));
        out.writeObject(obj);
        Boolean obj2 = (Boolean) in.readObject();
        System.out.printf("%24s:receiver: %s\n", "", System.identityHashCode(obj2));
        System.out.printf("%24s:same?:    %s\n", "", (obj == obj2));
        System.out.printf("%24s:equals?:  %s\n", "", (obj.equals(obj2)));
    }

}

これをJDK 5.0 Update 11で実行した結果。

java.version:   1.5.0_11
java.vm.vendor: Sun Microsystems Inc.

            Boolean.TRUE:sender:   11077203
                        :receiver: 6336176
                        :same?:    false
                        :equals?:  true
           Boolean.FALSE:sender:   23899971
                        :receiver: 6718604
                        :same?:    false
                        :equals?:  true
      new Boolean(false):sender:   8918002
                        :receiver: 30771886
                        :same?:    false
                        :equals?:  true

"same?"のところの結果を見て分かるとおり、異なるオブジェクトであることが分かる。
で、JDK 5.0 Update 11のソースを見てみると、確かにデシリアライズの際に特別なことを行うコードは一切ない。