Java ObjectOutputStream方法的defaultWriteObject和writeObject之间的区别和相似之处

时间:2018-08-22 06:24:22

标签: java serialization

我正在尝试理解Java序列化机制,我对此几乎没有疑问和错误。“ java.io.NotActiveException:不能调用writeObject”

    package serialization;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;

public class WriteObject{

    private void writeObject(ObjectOutputStream oos)
            throws IOException {
                // default serialization 
        oos.defaultWriteObject();
        Address address = new Address();
           address.setStreet("wall street");
           address.setCountry("united states");
           address.setNameofperson("nameofperson");
                oos.writeObject(address);}

    public static void main (String args[]) {

       Address address = new Address();
       address.setStreet("wall street");
       address.setCountry("united states");
       address.setNameofperson("nameofperson");
       //address.pet="lucy";
       WriteObject wr= new WriteObject();

       try{
 File f = new File("C:fileaddress.ser");
 //f.createNewFile();
        FileOutputStream fout = new FileOutputStream(f);
        ObjectOutputStream oos = new ObjectOutputStream(fout);  
        wr.writeObject(oos);

        //oos.defaultWriteObject();
        oos.close();
        System.out.println("Done");

       }catch(Exception ex){
           ex.printStackTrace();
       } 
    }
}

我收到以下错误:

    constructor default pers
constructor default add
java.io.NotActiveException: not in call to writeObject
    at java.io.ObjectOutputStream.defaultWriteObject(Unknown Source)
    at serialization.WriteObject.writeObject(WriteObject.java:13)
    at serialization.WriteObject.main(WriteObject.java:34)

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

  • 为什么我们使用oos.defaultWriteObject();?根据{{​​3}},此处存在向后兼容性。我还不太了解它是如何实现的。序列化的不兼容更改之一是删除较新版本中的字段。这意味着旧版本将不得不设置有时对用户无效的默认值。这与新版本添加一个新字段并允许设置默认值有何不同?
  • 在自定义序列化过程中,同时使用oos.defaultWriteObject();oos.writeObject(address);会不会有什么区别?我的意思是都将所有超类和当前类的非瞬态非静态字段都写入OOS。
  • 这是可能无法回答我的问题的重复问题列表。
  • this post表示*如果在写入可选数据(如果有)之前未调用defaultWriteObject或writeFields,那么在ObjectInputStream *的情况下实例反序列化的行为是不确定的,但我仍然可以调用writeObject不使用deafultwriteobject.right吗?
  • question 1这些答案表明,defaultwriteobject方法将写入一些额外的数据以进行流式传输,并以反射方式检查要写入的内容。 oos.writeobject(object obj)是否也进行反思性检查?

1 个答案:

答案 0 :(得分:0)

您的问题

  1. writeObject不是为了向后兼容。 readObject是。
  2. 它们是相同的。 defaultWriteObject可以帮助您快速编写“可序列化”的值。

向后兼容

考虑您的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只是为了使您免于编写无聊的代码。