【问题标题】:differences and similarities between defaultWriteObject and writeObject of java ObjectOutputStream methodsjava ObjectOutputStream方法的defaultWriteObject和writeObject的异同
【发布时间】:2019-12-25 18:12:16
【问题描述】:

我正在尝试了解java序列化机制,我有几个疑问

请回答以下有关 java 序列化的问题:

  • 为什么我们使用oos.defaultWriteObject();?根据this post,它在那里是为了向后兼容。而且我不太明白它是如何实现的。序列化的不兼容更改之一是删除较新版本中的字段。这意味着旧版本必须设置有时对用户无效的默认值。这与添加新字段并允许设置默认值的新版本有何不同?
  • 在自定义序列化期间,同时使用oos.defaultWriteObject();oos.writeObject(address); 有什么不同吗?两者的作用不同吗?我的意思是两者都将所有超类和当前类的非瞬态非静态字段写入OOS。

这里

private void writeObject(java.io.ObjectOutputStream stream)
        throws IOException {
    stream.writeObject(name);
    stream.writeInt(id);
    stream.writeObject(DOB);
}

private void readObject(java.io.ObjectInputStream stream)
        throws IOException, ClassNotFoundException {
    name = (String) stream.readObject();
    id = stream.readInt();
    DOB = (String) stream.readObject();
}

上面的代码产生的结果与下面的代码相同

private void writeObject(java.io.ObjectOutputStream stream)
            throws IOException {
        stream.defaultWriteObject();
    }

    private void readObject(java.io.ObjectInputStream stream)
            throws IOException, ClassNotFoundException {
         stream.defaultReadObject();
    }

何时使用这两种方法,何时使用 writeObject(employee);//employee 是我的整个对象//

  1. 这是无法回答我的问题的可能重复问题的列表。
  2. question 1 它说 * 如果在写入可选数据(如果有)之前未调用一次 defaultWriteObject 或 writeFields,那么在 ObjectInputStream* 但我仍然可以在不使用 deafultwriteobject.right 的情况下调用 writeObject 的情况下,实例反序列化的行为是未定义的?
  3. question 2 这些答案说 defaultwriteobject 方法将一些额外的数据写入流,并反射性地检查要写入的内容。 oos.writeobject(object obj) 不也反射检查吗?
  4. 最后我可以通过重写 writeObject 和 ReadObject 方法来控制我的序列化,那么 Externalizable 的意义何在?
  5. 如果提供串行 versionUID 不会引发异常,如果我反序列化具有该字段的旧类中缺少字段的对象会发生什么,基本上,如果我提供自己的 SerialverUID,所有不兼容的更改会发生什么?是否拥有自己的串行版本 UID 不会为所有兼容更改引发流损坏异常?

【问题讨论】:

  • @eugene 你们能帮我吗?
  • 引用的向后兼容性是指与没有自定义的类的先前版本 writeObject() 方法的兼容性,但这还不是全部。当您想要默认的序列化操作加上一些您自己的时,它会在自定义writeObject() 方法中调用。所有这些都有记录。当您在该上下文之外调用它时,正如您所拥有的那样,您会得到该异常。这也被记录在案。就像你问的其他一切一样。请参阅对象序列化规范。
  • @user207421 我确实浏览了文档,我在这里进行澄清。如果 defaultwriteobject 用于自定义序列化,那么为什么我们有可外部化的接口?我们可以简单地重写 writeobject 方法
  • 我不建议向您重复解释我提到的文档中已经完全涵盖的内容。

标签: java oop serialization stream bytestream


【解决方案1】:

关于您的问题

  1. writeObject 不是为了向后兼容。 readObject 是。
  2. 它们是相同的。 defaultWriteObject 是为了帮助你快速编写“serialzable”值。

向后兼容性

考虑你的 bean 添加了一个新字段。

class Bean implements Serializable {
  int id;
  String name;
  String newValue = "123";
}

虽然你给了newValue默认值,java序列化会忽略它。 (因为它分配实例而不是new它)

现在如果你不使用readObject,你会得到newValue=null。所以你还需要在readObject 进行初始化。

  private void readObject(ObjectInputStream stream) throws Exception {
    stream.defaultReadObject();
    this.newValue = "123";
  }

defaultWriteObject 如何帮助您

考虑您的 bean 几乎是“可序列化的”,除了某些字段。

请参阅以下代码。 BadThing 不是 Serializable 或者它有一些你不想序列化的敏感数据。

class Bean implements Serializable {
  int id;
  String string;
  BadThing badThing;
}

为了快速序列化它,你可以让字段transient 并编写你的writeObject 方法来处理它

  private void writeObject(ObjectOutputStream stream) throws Exception {
    stream.defaultWriteObject();
    stream.writeInt(badThing.id);
  }

  // Corresponding `readObject`

当然你可以把defaultWriteObject换成几个writeXXX。但是如果你有很多很多领域,写代码很累很无聊,对吧?

所以defaultWriteObject 只是为了让你免于编写无聊的代码。

【讨论】:

    猜你喜欢
    • 2014-04-16
    • 2018-09-23
    • 2011-05-22
    • 1970-01-01
    • 2013-11-20
    • 2016-02-03
    • 2023-03-26
    • 2015-01-09
    • 1970-01-01
    相关资源
    最近更新 更多