更改实例状态不会反映在序列化对象中

时间:2014-12-18 09:02:03

标签: java serialization deserialization objectinputstream objectoutputstream

我写了以下简单代码

public static void main(String args[]) throws FileNotFoundException, IOException, ClassNotFoundException
{
    ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(new File("data.txt")));
    Human human = new Human();
    human.setAge(21);
    human.setName("Test");
    System.out.println("Human : " + human);
    oos.writeObject(human);
    human.setName("Test123");
    oos.writeObject(human);
    ObjectInputStream ois = new ObjectInputStream(new FileInputStream(new File("data.txt")));
    Human newHuman1  = (Human)ois.readObject();
    System.out.println("newHuman1 :" + newHuman1);
    Human newHuman2  = (Human)ois.readObject();
    System.out.println("newHuman2 :" + newHuman2);
}

并打印 -

Human : Human [age=21, name=Test]
newHuman1 :Human [age=21, name=Test]
newHuman2 :Human [age=21, name=Test]

我无法理解为什么不打印

newHuman2 :Human [age=21, name=Test123]

为什么更改实例状态不会反映在序列化对象中?

1 个答案:

答案 0 :(得分:5)

你已经将对象写了两次,但只回读第一个。因此,如果写入了两个对象副本,则需要添加第二个读取以查看第二个副本。在从文件读取之前关闭输出可能是个好主意,以确保刷新缓冲区。

但是所有这一切:ObjectOutputStream只写一个给定的对象,然后对同一个对象的后续写入将引用写入它,而不是它的第二个副本。来自the documentation

  

对象的默认序列化机制会写入对象的类,类签名以及所有非瞬态和非静态字段的值。对其他对象的引用(瞬态或静态字段除外)也会导致写入这些对象。使用引用共享机制对单个对象的多个引用进行编码,以便可以将对象图形恢复为与写入原始图像时相同的形状。

这个想法是你将一次序列化对象图。在序列化期间改变对象图是一件非常奇怪的事情。我找不到任何文档说它不受支持,但是在项目中添加第二个读取仍然显示“Test”而不是“Test123”,所以......

要写出两个单独的Human个对象,您需要在编写之前创建第二个对象:

import java.io.*;

public class Human implements Serializable {
    private int age;
    private String name;

    public void setAge(int a) {
        this.age = a;
    }

    public void setName(String n) {
        this.name = n;
    }

    public String toString() {
        return "[Human " + this.age + ", " + this.name + "]";
    }

    public static void main(String args[]) throws FileNotFoundException, IOException, ClassNotFoundException
    {
        try (ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(new File("data.txt"))))
        {
            Human human = new Human();
            human.setAge(21);
            human.setName("Test");
            System.out.println("Human : " + human);
            oos.writeObject(human);
            human = new Human(); // <== Change
            human.setAge(21);    // <== Change
            human.setName("Test123");
            oos.writeObject(human);
        }
        try (ObjectInputStream ois = new ObjectInputStream(new FileInputStream(new File("data.txt"))))
        {
            Human newHuman  = (Human)ois.readObject();
            System.out.println("newHuman1 :" + newHuman);
            newHuman  = (Human)ois.readObject();
            System.out.println("newHuman2 :" + newHuman);
        }
    }
}

如果上面没有标记这些行,则第二次写入只会导致对第一个对象的引用。我们可以证明这样:

public static void main(String args[]) throws FileNotFoundException, IOException, ClassNotFoundException
{
    try (ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(new File("data.txt"))))
    {
        Human human = new Human();
        human.setAge(21);
        human.setName("Test");
        System.out.println("Human : " + human);
        oos.writeObject(human);
        human.setName("Test123");
        oos.writeObject(human);
    }
    try (ObjectInputStream ois = new ObjectInputStream(new FileInputStream(new File("data.txt"))))
    {
        Human newHuman1  = (Human)ois.readObject();
        System.out.println("newHuman1 :" + newHuman1);
        Human newHuman2  = (Human)ois.readObject();
        System.out.println("newHuman2 :" + newHuman2);
        System.out.println("Same object? " + (newHuman1 == newHuman2));
    }
}

......输出:

Human : [Human 21, Test]
newHuman1 :[Human 21, Test]
newHuman2 :[Human 21, Test]
Same object? true