Java 提供了一种对象序列化的机制。用一个字节序列可以表示一个对象,该字节序列包含该对象的数据、对象的类型和对象中存储的属性等信息。字节序列写出到文件之后,相当于文件中持久保存了一个对象的信息。

反之,该字节序列还可以从文件中读取回来,重构对象,对它进行反序列化。对象的数据、对象的类型和对象中存储的数据信息,都可以用来在内存中创建对象。看图理解序列化:
序列化流与反序列化流 - 图1

1.对象序列化流ObjectOutputStream


java.io.ObjectOutputStream 类,将Java对象的原始数据类型写出到文件,实现对象的持久存储。

构造:
public ObjectOutputStream(OutputStream out);

方法:
public void writeObject(Object obj);//将对象写出去

注意事项:
被序列化的对象所属的类 必须实现java.io.Serializable接口以启动其序列化功能, 否则,会抛出NotSerializableException,而java.io.Serializable接口成为标记接口,没有任何抽象方法需要重写


2.对象反序列化流ObjectInputStream


ObjectInputStream反序列化流,将之前使用ObjectOutputStream序列化的原始数据恢复为对象。
作用: 从文件中读取对象

构造:
public ObjectInputStream(InputStream in): 创建一个指定InputStream的ObjectInputStream。
方法:
public final Object readObject () : 读取一个对象
注意事项:

序列化时对象所属的类和反序列化时对象所属的类如果不一致,就会抛出InvalidClassExcetoin.



Java如何判断 序列化时对象所属的类 和 反序列化时 对象所属的类 是不一致的呢???

当某个类实现java.io.Serializable接口时,JVM会自动给该类添加一个静态的long类型的整数变量 long serialVersionUID,代表该类的版本号, 当我们修改类时,版本号会重新计算,跟原来是不一样的,当序列化 和 反序列化 时 会对比serialVersionUID,如果发现不一样,会抛出InvalidClassExcetoin异常.

以上Java的版本号管理是非常糟糕的,Java提供了一个由程序员手动管理版本号的方式,在类上有一个警告,点击警告,自动生成版本号即可.

对于JVM可以反序列化对象,它必须是能够找到class文件的类。如果找不到该类的class文件,则抛出一个 ClassNotFoundException 异常。



3.序列化接口(主要是介绍两个异常)

NotSerializableException: 当序列化对象所属类没有实现java.io.Serializable

InvalidClassExcetion: 当序列化时的版本号 和 反序列化时类的版本不一致时


扩展:
使用序列化流 写多个对象是没有问题的

但是反序列化流 读取多个对象就会抛出 文件找不到末尾异常

因为在于,写多个对象时,文件的末尾标记会被删除

解决方案:
a.自己相办法写一个文件结束标记
b.使用集合存储多个对象,再把集合对象写入文件
c.使用数据库保存多个对象

4.瞬态关键字transient


transient关键字用来修饰成员变量的,被transient修饰的成员变量 和 不被transient修饰的成员变量 没有任何不同,被序列化时,序列化流会自动忽略该成员变量,也就是这个成员变量的值为null.
参考:
https://blog.csdn.net/qq_44543508/article/details/103232007