Java套接字/序列化,对象不会更新

14

我正在编写一个基于socket的小程序。我使用了一个名为ModelEvent的类来通过socket传递信息。在ModelEvent内部,有一个类型为(Object)的变量object。

这个对象本身是一个带有一些值的2D数组。

object[1][2] = 2;
ModelEvent event = new ModelEvent("allo", object);
dispatchEvent(event);

object[2][3] = 2;
ModelEvent event2 = new ModelEvent("you", object);
dispatchEvent(event2);

假设数组对象被填充了值为1。第一个事件由客户端收到,数据是正确的。然而第二个事件传输的数据不正确。它的数据和第一个事件中的相同。我使用了“allo”和“you”,以确保我没有重复读取同一个事件。答案是否定的。字符串没问题,但对象不行,即使已经更新过。在发送第二个事件之前,我遍历了数组,以查看其在服务器端是否更新,发现已经更新。但在客户端仍然与第一个事件中相同,即使事件本身已更改。


你是如何在客户端读取它的? - Vincent Ramdhanie
ObjectInputStream.readObject并将其强制转换 - maniak
2个回答

29

请参考ObjectOutputStream.reset

重置将忽略已写入流的任何对象的状态。状态将重置为与新的ObjectOutputStream相同。流中的当前点被标记为重置,因此相应的ObjectInputStream也将在相同点重置。以前写入流的对象不会被视为已经在流中。它们将再次写入流。

/* prevent using back references */
output.reset();
output.writeObject(...);

在将同一对象写入序列化之前,请调用reset以确保其更新状态被序列化。否则,它将仅使用对先前写入的具有过时状态的对象的后向引用。

或者,您可以按以下方式使用 ObjectOutputStream.writeUnshared

将一个“未共享”的对象写入ObjectOutputStream。该方法与writeObject相同,只是它总是将给定对象作为流中的新唯一对象写入(而不是指向先前序列化实例的后向引用)。
具体来说:
通过writeUnshared写入的对象始终以与新出现的对象(尚未写入流的对象)相同的方式进行序列化,无论该对象是否已经被先前写入。
如果使用writeObject写入了先前使用writeUnshared写入的对象,则先前的writeUnshared操作将被视为对单独对象的写入。换句话说,ObjectOutputStream永远不会生成对由调用writeUnshared写入的对象数据的后向引用。
通过writeUnshared编写对象本身并不能保证在反序列化时获得唯一引用,但它允许在流中多次定义单个对象,因此接收者对readUnshared的多次调用不会发生冲突。请注意,上述规则仅适用于使用writeUnshared编写的基本级别对象,而不适用于要序列化的对象图中任何传递引用的子对象。
output.writeUnshared(...);

请注意,最好将此与ObjectInputStream.readUnshared相结合使用。
ObjectInputStream中读取一个“未共享”的对象。此方法与readObject相同,不同之处在于它防止随后调用readObject和readUnshared返回通过此调用获得的反序列化实例的其他引用。
具体而言:
- 如果调用readUnshared来反序列化回溯引用(先前已写入流的对象的流表示形式),则会抛出ObjectStreamException。 - 如果readUnshared成功返回,则任何后续尝试将回溯引用反序列化到由readUnshared处理的流句柄将导致抛出ObjectStreamException。
通过readUnshared反序列化对象会使与返回对象关联的流句柄无效。请注意,这本身并不总是保证readUnshared返回的引用是唯一的;反序列化对象可能定义了一个readResolve方法,该方法返回对其他方可见的对象,或者readUnshared可能返回可以在流中的其他位置或通过外部手段获得的Class对象或枚举常量。如果反序列化对象定义了一个readResolve方法,并且该方法的调用返回一个数组,则readUnshared返回该数组的浅克隆;这保证了返回的数组对象是唯一的,并且即使底层数据流已被操作,也不能从ObjectInputStream上的readObject或readUnshared调用中第二次获取该数组对象。
obj = input.readUnshared();

5
我现在想吻你!无恋爱意味 谢谢。只是想确认一下,当一个对象被两次发送到流中时,它会记住先前的状态并使用旧状态? - maniak
1
是的,它确实可以 :)!我认为这是出于性能考虑,但它并不适合您想要使用它的方式。 - Mickäel A.
我调试了我的代码大约100次,我以为自己做错了什么,但实际上只需要reset()流就好了。谢谢。 - Youssef N

4

我没有看到dispatchEvent代码,但根据你所写的我假设以下: 你写了相同的对象(只是状态改变了),这意味着它将仅写入两次引用。你可以在Java输出流文档中查看(有关性能)。

你应该使用writeUnshared(),这将在每次写入时创建一个新对象

我看到建议使用reset,这将使您达到相同的结果,但会对性能产生影响。


+1 指出性能影响。当您发布时,我正在修改我的答案以包括 writeUnshared - obataku
2
writeUnshared()和reset()/writeObject()之间唯一的区别在于,在第一种情况下,引用对象仍可以作为句柄发送。这是一个重大的功能差异,可能根本不是OP想要的。将所有这些简化为仅仅是“性能影响”是完全不正确和完全误导的。 - user207421

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接