(java) ObjectInputStream deserializing wrong version of object [duplicate]

血红的双手。 提交于 2019-11-27 07:46:10

问题


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()


回答1:


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).




回答2:


Are you using read() or readObject() from ObjectInputStream? If you're using read() then you're just getting a single byte of data. Try converting the client

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

EDIT: should've been input.readObject();




回答3:


So many hours I've spent debugging some code like this. :)

I'm not sure what the proper solution to this is, but if you create a new instance of the object, or just clone() it, before sending it the code should work as expected.

It seems as if the VM recognizes the object it is receiving as one that it already has, and simply updates the pointer at the client without bothering to actually check if there are any changes.

try...

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


来源:https://stackoverflow.com/questions/6352540/java-objectinputstream-deserializing-wrong-version-of-object

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!