java中序列化和反序列化

序列化和反序列化

​ 序列化是一种持久化手段,普遍应用于网络传输,RMI等场景中。

1,java对象的序列化

​ 在java程序中运行期间,允许我们进行java对象的创建,但是只有jvm运行时这些对象才可能存在,即是这些对象的生命周期不可能比jvm的生命周期更长。但在实际应用中我们可能需要在jvm停止运行后能够保存指定的对象信息(持久化)。

​ 使用java对象序列化,在保存对象时,会把对象的状态保存为一组字节,反序列化再将这些字节组装成对象。这里需要注意的是,对象序列化保存的是对象的状态,即对象的成员变量。对象序列化时不会关注类中的静态变量(即是序列化不会将静态变量进行保存)

​ 对象序列化就是将object转化成byte序列,反之称为对象的发序列化。对象序列化可以将某个对象转化成便于在网络中进行传输的byte(字节)序列。在使用RMI(远程方法调用),或者在网络中传递对象时,也会用到对象序列化。

​ 若对一个object进行序列化,该对象的所属的类必须实现Serializable接口。该接口没有声明任何方法,仅仅起到一个标志的功能。但是一个对象进行序列化,其所属类实现Serializable接口是必须的,否则将会抛出 java.io.NotSerializableException异常。

​ ObjectOutputStream:对象输出流,用于将对象序列化。

​ ObjectInputStream:对象输入流,用于将对象进行反序列化。

​ transient关键字:被修饰的属性不会进行jvm默认的序列化(不代表不能序列化,可以自定义序列化方式,见ArrayList中的样例)。在反序列化时该属性会被设置为该类型的默认值。若需要通过transient关键字实现自定义序列化和反序列化过程(比如对某个敏感字段,such as密码字段,进行加密之后再序列化),则需要在对象所属的类中实现writeObject和readObject方法。如下所示:

  //自定义序列化方式
private void writeObject(java.io.ObjectOutputStream s) throws IOException{
      s.defaultWriteObject();   //对未被transient修饰的属性进行默认序列化
      s.writeInt(age);
}

//自定义反序列化方式
private void readObject(java.io.ObjectInputStream s) throws IOException,ClassNotFoundException{
      s.defaultReadObject();
      this.age=s.readInt();
}

​ 在序列化过程中,如果被序列化的类中定义了readObject和writeObject方法,则jvm会调用该类中的这两个方法,对该类的对象进行序列化和反序列化。如果被序列化的类中没有这两个方法,则默认调用ObjectOutputStream中的defaultWriteObject()和ObjectInputStream中的defaultReadObject()方法进行序列化和反序列化。

如果一个类中包含了writeObject和readObject方法,那么在序列化和反序列化的时候这两个方法是怎么被调用的呢?

​ 如果一个类中包含了这两个方法,则在使用ObjectInputStream中的writeObject()和ObjectOutputStream中的readObject()时会通过反射的方式进行调用类中的这两个方法。

一个类实现了序列化接口,其子类都可进行序列化。对子类对象进行反序列化时,如果父类没有实现Serializable接口,则父类的构造函数会被调用。

你可能感兴趣的:(java)