(java)ObjectInputStream反序列化错误版本的对象 [英] (java) ObjectInputStream deserializing wrong version of object

查看:238
本文介绍了(java)ObjectInputStream反序列化错误版本的对象的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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



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



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



所以例如,我有一个类的实例,其公共intvar等于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 ......无限增加,而客户的输出仅为1,1,1,1,1,1,1等。



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



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

解决方案

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

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



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


I'm just learning networking from a java book, so I'm a bit of a noob. I couldn't find this problem in the book or online so I decided to ask the internet.

The book says to use the ObjectOutputStream and ObjectInputStream to send and receive objects to different consoles.

Now, I'm able to successfully receive the objects I send-- but only once. When I send different objects: random strings and Integers and nameless instances, the console has all the correct fields. But when I send an instance of an object, change the value of one of the instance's fields, and resend the object, then the inpustream loads the original instance's values.

So, say for example, I had an instance of a class with a public int "var" equal to 1. If I send the instance of this class, the client receives it and correctly reports that var = 1. However, if I change var to 2 (in the same instance) and resend it, the client will finish calling the read() method (so it must have received the new object!), but it will report var as being 1. If I send the instance to a different client who has not yet received the instance, it will correctly report var as 2, and it will continue to report it as 2 even if I change var.

The fact that the client reads the correct version of the instance if it hasn't received it before must mean that the object is being properly sent through the outputstream; for some reason the inputstream just isn't working. It's almost like it sees that its the same object so it assumes that it has the same values without checking. Why does this happen and how can I fix it?

Sorry if I'm asking something stupid- the book doesn't explain how serialization and sockets work, just how to use them, so I could very well be fundamentally confused about how to use them. Thank you!

Simple code that I wrote to test the problem:

Server: (has a timer action to keep sending updated objects)

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

Client

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

When these programs run the output for the Server class is 1,2,3,4... increasing infinitely, while the Client's output is just 1,1,1,1,1,1,1,etc.

Thank you for taking the time to read this. Sorry if I'm just being dumb, I'm new to this stuff.

EDIT: Sorry, the the read() was a mistype (i manually typed the code because i couldn't eget the formatting right), I meant input.readObject()

解决方案

The reason is that ObjectOutputStream caches object references and writes back-references to the stream if the same object is written twice. That means when you call write the second time the stream doesn't actually write a new copy of the object, it just inserts a reference to the object that it's already written.

You can prevent this by calling ObjectOutputStream.reset between calls to write. That tells the stream to discard any cached references.

This behaviour seems strange but it's actually necessary to prevent infinite loops if you try to serialize an object graph that has circular references (i.e. write object A that refers to object B that in turn refers back to object A).

这篇关于(java)ObjectInputStream反序列化错误版本的对象的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆