2011-06-15 61 views
5

我刚刚从一本java书籍学习网络,所以我有点小菜鸟。我无法在书中或在网上找到这个问题,所以我决定询问互联网。(java)ObjectInputStream反序列化对象的错误版本

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

现在,我能够成功接收我发送的对象 - 但只有一次。当我发送不同的对象:随机字符串和整数以及无名的实例时,控制台具有所有正确的字段。但是,当我发送一个对象的实例时,更改其中一个实例字段的值并重新发送该对象,然后inpustream加载原始实例的值。例如,假设我有一个public 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); 
      } 
    } 

当这些程序运行服务器类的输出是1,2,3,4 ...无限增加,而客户端的输出只是1,1,1,1,1,1,1等。

感谢您花时间阅读本文。对不起,如果我只是愚蠢的,我是新来的这个东西。

编辑:对不起,读()是由打字错误(我手动键入的代码,因为我不能eget正确的格式),我的意思是input.readObject()

+0

相关问题:http://stackoverflow.com/questions/15675262/。 – 2016-07-18 04:18:44

回答

-1

这么多小时我已经花了调试这样的代码。 :)

我不知道什么是适当的解决方案,但如果您创建对象的新实例,或者只是克隆它(),在发送它之前,代码应该按预期工作。

看起来好像虚拟机识别它正在接收的对象是它已经拥有的对象,并且只是更新客户端上的指针而不打扰实际检查是否有任何更改。

尝试...

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

一个小货物崇拜节目永远不会伤害,呃? – 2011-06-15 03:40:01

+0

经过足够的时间在桌面上敲打头部,试图弄清楚为什么在服务器端打印所有字段会给您带来与在客户端打印所有字段不同的结果,加入邪教组织似乎是一个好主意。 ;) – Mike 2011-06-15 03:45:20

+4

'ObjectOutputStream.reset'是正确的解决方案:) – 2011-06-15 03:58:39

3

您是否使用从ObjectInputStream的read()readObject()?如果你使用read(),那么你只是得到一个字节的数据。尝试转换客户端

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

编辑:应该已经input.readObject();

+0

你的意思是改变代码为'input.readObject()'? – Bohemian 2011-06-15 03:22:24

+0

是的......谢谢你看到我的疏忽。我将编辑。 – Suroot 2011-06-15 03:23:52

+0

谢谢你。 read()返回一个int是如此的误导。把所有Java类型检查浪费。 – navjotk 2013-12-05 11:59:59

12

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

您可以通过调用要写入的调用之间的ObjectOutputStream.reset来阻止此操作。这告诉流放弃任何缓存的引用。

这种行为似乎很奇怪,但如果您尝试序列化具有循环引用的对象图形(即写入对象A引用对象B,然后引用对象A),则实际上有必要防止出现无限循环。

+0

这工作!谢谢! – superzipzop 2011-06-15 04:09:21

+0

不要忘记接受答案:)只需点击您最喜欢的答案旁边的复选标记。 – 2011-06-15 04:11:46

+0

你刚刚解决了我一直在努力工作数小时的问题!非常感谢! – 2013-11-20 05:59:21