【问题标题】:Java socket/serialization, object won't updateJava套接字/序列化,对象不会更新
【发布时间】:2012-09-02 16:39:06
【问题描述】:

我正在编写一个基于套接字的小程序。我正在使用类 ModelEvent 通过套接字传递信息。在 ModelEvent 内部,有一个(Object)类型的变量对象。

对象本身是一个带有一些值的二维数组。

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。第一个事件(event)被客户端接收到,数据是对的。通过数据发送的第二个事件不正确。它的数据与第一次调度中的相同。 “allo”和“you”是看我是否没有两次阅读同一个事件,答案不是。字符串是正确的,但对象不是,如果它已更新,则事件。我在发送第二个事件之前遍历数组以查看它是否在服务器端更新,并且确实如此。但在客户端,即使事件本身发生了变化,它仍然与第一次分派时一样。

【问题讨论】:

  • 你在客户端读的怎么样?
  • ObjectInputStream.readObject 我投了它

标签: java sockets serialization


【解决方案1】:

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 相同,只是它阻止对 readObjectreadUnshared 的后续调用返回对通过此调用获得的反序列化实例的附加引用。

具体来说:

  • 如果调用 readUnshared 来反序列化反向引用(之前已写入流的对象的流表示),将抛出 ObjectStreamException
  • 如果readUnshared 成功返回,则任何后续尝试反序列化对readUnshared 反序列化的流句柄的反向引用都会导致ObjectStreamException 被抛出。

通过readUnshared 反序列化对象会使与返回对象关联的流句柄无效。请注意,这本身并不总是保证readUnshared 返回的引用是唯一的;反序列化的对象可以定义一个readResolve 方法,该方法返回一个对其他方可见的对象,或者 readUnshared 可以返回一个Class 对象或enum 常量,可在流中的其他地方或通过外部方式获得。如果反序列化对象定义了一个readResolve 方法并且该方法的调用返回一个数组,那么readUnshared 返回该数组的一个浅层克隆;这保证了返回的数组对象是唯一的,并且即使底层数据流已被操纵,也无法通过调用readObject 或在ObjectInputStream 上的 readUnshared 再次获得。

obj = input.readUnshared();

【讨论】:

  • 我现在就想亲你! 没有同性恋 谢谢。只是为了理解,当一个对象被发送两次到流中时,它会记住它之前的状态并使用旧的状态?
  • 是的 :) !我认为这是出于性能原因,但它不适合您想要的用途。
  • 很好的答案。我调试了我的代码 100 次,我以为我做错了什么,我只需要 reset() 流谢谢
【解决方案2】:

我没有看到 dispatchEvent 代码,但是根据您所写的内容,我假设如下: 你写同一个对象(只是它的状态改变了),这意味着它只会写两次引用。您可以在 java 输出流文档中看到(用于性能)。

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

我看到有人建议重置,这将使您获得相同的结果,但它会影响性能。

【讨论】:

  • +1 用于指出性能影响。当您发布时,我正在修改我的答案以包含 writeUnshared
  • -1 表示“性能影响”。 writeUnshared() 和 reset()/writeObject() 之间的唯一区别是,在第一种情况下,引用的对象仍可以作为句柄发送。这是一个主要的 功能 差异,它可能根本不是 OP 想要的。将所有这些都归结为“性能影响”是完全不正确的,而且完全具有误导性。
猜你喜欢
  • 2015-03-04
  • 2012-11-02
  • 2018-10-15
  • 2013-11-27
  • 2011-06-21
  • 1970-01-01
  • 2013-07-08
相关资源
最近更新 更多