【源码系列-1】Serializable

  • 序列化:
    序列化是指把对象转换为字节序列的过程,我们称之为对象的序列化,就是把内存中的这些对象变成一连串的字节(bytes)描述的过程。

  • 反序列化:
    就是把持久化的字节文件数据恢复为对象的过程。那么什么情况下需要序列化呢?大概有这样两类比较常见的场景:1)、需要把内存中的对象状态数据保存到一个文件或者数据库中的时候,这个场景是比较常见的,例如我们利用mybatis框架编写持久层insert对象数据到数据库中时;2)、网络通信时需要用套接字在网络中传送对象时,如我们使用RPC协议进行网络通信时;

  • 序列化的应用场景:
    实现serializabel接口的作用是就是可以把对象存到字节流,并且可以恢复,是实现持久化和持久化和网络传输的基础,要持久化和网络传输就得转为字节流,应用于分布式应用中及涉及数据持久化的场景。

  • 实现java.io.Serializable接口的类可以进行序列化。

  • 这个接口没有任何方法,只是语义上表面这个实现类可以进行序列化。

  • 一个没有实现序列化的子类想要实现序列化的话,必须保存父类的public,protected作用域。这样做的前提是父类有无参构造函数,否则会在运行时报错。

  • 在反序列化的过程中,无法实现序列化的类将通过public或protected无参构造函数初始化,可序列化的子类将会被存储在流中。

  • 当对图片进行转换的时候,对象可能会不支持序列化接口,会抛出NotSerializableException异常。

  • 序列化或反序列化的类需要实现以下方法:

    • private void writeObject(java.io.ObjectOutputStream out) throws IOException
    • private void readObject(java.io.ObjectInputStream in) throws IOException, ClassNotFoundException;
    • private void readObjectNoData() throws ObjectStreamException;
  • writeObject方法用来写对象的状态,以便readObject可以恢复对象状态。默认的保存对象状态的机制是调用out.defaultWriteObject。这个方法不关注状态是属于子类还是父类,保存状态的两种方法:

    1. 使用writeObject把作用域写入ObjectOutputStream
    2. 使用DataOutput支持的方法
  • readObject方法通过读取流恢复类作用域。默认的恢复对象的非静态和非暂时域是通过调用in.defaultReadObject实现的。defaultReadObject方法给保存在流里面的对象赋作用域。这个方法不关心状态是属于父类还是子类。

  • readObjectNoData方法在父类没有被序列化的情况下,用来初始化该类对象的状态。当序列化使反序列化的实例的类版本与方法接收到的不一致时,或者是序列化后的二进制流被窜改也会调用readObjectNoData方法。

  • serialVersionUID用于对序列化的类做版本标识,在反序列化的过程中验证是否为对象加载了与序列化兼容的类。如果receiver加载的类和sender加载的类的serialVersionUID不同,反序列化会报InvalidClassException。因此,在序列化之前,应该在类里生命一个serialVersionUID成员变量。

  • private static final long serialVersionUID = 42L;

  • 如果没有显式声明,则在运行时会分配一个默认的serialVersionUID,因为serialVersionUID的计算可能会因编译器的不同而不同,可能会报InvalidClassException,因此建议在序列化时显式声明serialVersionUID,且应该使用private修饰符,以免该属性被子类继承。

猜你喜欢

转载自blog.csdn.net/u010659877/article/details/104369247