(java)ObjectInputStream反序列化错误版本的对象

时间:2011-06-15 02:56:05

标签: java serialization objectinputstream

我刚刚从一本java书中学习网络,所以我有点像菜鸟。我无法在书中或网上找到这个问题所以我决定上网。

本书说使用ObjectOutputStream和ObjectInputStream来发送和接收不同控制台的对象。

现在,我能够成功接收我发送的对象 - 但只能一次。当我发送不同的对象:随机字符串和整数和无名实例时,控制台具有所有正确的字段。但是当我发送一个对象的实例时,更改一个实例的字段的值,然后重新发送该对象,然后inpustream会加载原始实例的值。

所以,例如,我有一个类的实例,其公共int“var”等于1.如果我发送此类的实例,客户端会收到它并正确报告var = 1。但是,如果我将var更改为2(在同一实例中)并重新发送它,客户端将完成调用read()方法(因此它必须已经接收到新对象!),但它会将var报告为1.如果我发送对于尚未收到实例的其他客户端的实例,它会正确地将var报告为2,即使我更改var,它也会继续将其报告为2。

如果客户端之前没有收到它,那么客户端读取正确版本的实例必须意味着该对象正在通过输出流正确发送;由于某种原因,输入流不起作用。它几乎就像它看到它是同一个对象所以它假定它具有相同的值而不进行检查。为什么会发生这种情况,我该如何解决?

很抱歉,如果我问一些愚蠢的东西 - 这本书没有解释序列化和套接字如何工作,只是如何使用它们,所以我很可能从根本上对如何使用它们感到困惑。谢谢!

我编写的用于测试问题的简单代码:

服务器:(具有继续发送更新对象的计时器操作)

    public void actionPerformed(ActionEvent e)
{
    object.var++;
            output.write(object);
            output.flush();
            System.out.println(object.var);
}

客户端

    public void run()
{
    while(true)
            {
                   Test t = (Test)input.readObject();
                   System.out.println(t.var);
            }
    }

当这些程序运行时,Server类的输出是1,2,3,4 ......无限增加,而Client的输出只是1,1,1,1,1,1,1等。

感谢您抽出宝贵时间阅读本文。对不起,如果我只是愚蠢,我是这个人的新手。

编辑:对不起,read()是一个错误的类型(我手动输入代码,因为我无法正确格式化),我的意思是input.readObject()

3 个答案:

答案 0 :(得分:15)

原因是ObjectOutputStream缓存对象引用,并且如果同一对象被写入两次,则会向流写入反向引用。这意味着当您第二次调用write实际上没有写入对象的新副本时,它只是插入对已经写入的对象的引用。

您可以通过在写入调用之间调用ObjectOutputStream.reset来防止这种情况。这告诉流丢弃任何缓存的引用。

这种行为看起来很奇怪,但是如果你试图序列化一个具有循环引用的对象图(即写入对象B,引用对象B又反过来引用对象A),则实际上有必要防止无限循环。

答案 1 :(得分:3)

您是否正在使用ObjectInputStream中的read()readObject()?如果您正在使用read(),那么您只需获取一个字节的数据。尝试转换客户端

public void run()
{
  while(true)
  { 
    Test t = (Test)input.readObject();
    System.out.println(t.var);
  }
}

编辑:应该是input.readObject();

答案 2 :(得分:-1)

我花了这么多时间来调试这样的代码。 :)

我不确定这个问题的正确解决方案是什么,但如果你创建了一个新的对象实例,或者只是克隆()它,那么在发送之前代码应该按预期工作。

似乎VM将其正在接收的对象识别为已有的对象,只需更新客户端的指针,而无需实际检查是否有任何更改。

尝试...

public void actionPerformed(ActionEvent e)
{
    object.var++;
    //assuming your object supports clone()
    output.write(object.clone());
    output.flush();
    System.out.println(object.var);
}