序列化是通过实现 java.io.Serializable
接口来实现的
序列化的作用
数据持久化:序列化可以将对象的状态转换为字节流,然后将这些字节流保存到文件或数据库中,实现数据的持久化存储。
网络传输:在网络通信中,序列化用于将对象转换为字节流,以便通过网络发送到其他计算机或设备,然后在接收端将字节流反序列化回对象。
分布式系统:在分布式系统中,序列化用于在不同的节点或服务之间传输对象状态,以实现数据的共享和同步。
跨语言交互:不同编程语言的系统可以通过序列化来交换数据。例如,一个Java对象可以被序列化,然后被Python程序反序列化。
序列化关键的接口和关键字
Serializable 接口:一个标记接口,用于指示一个类可以被序列化。实现此接口的类的对象可以被 ObjectOutputStream
类的实例写入,并可以通过 ObjectInputStream
类的实例读出。
ObjectOutputStream:用于将Java对象的原始数据类型写入到输出流中。这是序列化的核心类。
ObjectInputStream:用于从输入流中读取Java对象的原始数据类型。它是反序列化的核心类。
writeObject 和 readObject 方法:这两个方法允许对象在序列化和反序列化过程中自定义其行为。它们可以是类的私有方法,并在类的内部调用。
transient 关键字:当成员变量声明为 transient
,它就不会被序列化。这意味着这个变量的值在反序列化后不会被恢复。
serialVersionUID:类似于类的版本号,用于在反序列化过程中确保发送和接收的类的版本兼容。
public static void main(String[] args) throws IOException {
Person person = new Person("Tom", 32);
FileOutputStream fileOutputStream = new FileOutputStream(new File("D:/person.txt"));
ObjectOutputStream objectOutputStream = new ObjectOutputStream(fileOutputStream);
objectOutputStream.writeObject(person);
objectOutputStream.close();
fileOutputStream.close();
System.out.println("over");
}
序列化的实现方式
类实现Serializable接口
Serializable接口是一个标记接口,不用实现任何方法。一旦实现了此接口,该类的对象就是可序列化的
类中属性的类型
如果一个可序列化的类的成员不是基本类型,也不是String类型,那这个引用类型也必须是可序列化的
自定义对象类型不可进行序列化,否则报错
对象的多次序列化
JVM是通过类名来区分Java类的,当具有相同的类名,JVM就会给类分配一个序列版本号来进行序列和反序列化的标识。
第一次序列化输出的是对象的序列化信息
接下来的就是输出JVM为该类分配的序列化版本号
第一种情况:没有指定序列版本号,JVM会自动为该序列对象分配一个序列版本号,若修改了类的信息,JVM会重新分配一个序列版本号,此时我们再用以往的反序列化代码进行反序列化就会报错
第二种情况:制定了版本序列号,JVM在进行序列和反序列化时,把版本序列号作为唯一标识,当你对类进行修改了,JVM会使用默认值,基本数据类型时‘0’,引用数据类型是'null',boolean类型默认是false
小技巧
父类实现了Serializable接口,子类自然隐式的实现类Serializable接口。
当一个类的属性基本不会进行更改,就可以对该类进行序列化,比如说项目中的实体类
当该类指定了序列化版本号(serialVersionUID),后续对该类更改属性了,依旧可以进行序列化和反序列化
总结
- 所有需要网络传输的对象都需要实现序列化接口,通过建议所有的javaBean都实现Serializable接口。
- 对象的类名、实例变量(包括基本类型,数组,对其他对象的引用)都会被序列化;方法、类变量、transient实例变量都不会被序列化。
- 如果想让某个变量不被序列化,使用transient修饰。
- 序列化对象的引用类型成员变量,也必须是可序列化的,否则,会报错。
- 反序列化时必须有序列化对象的class文件。
- 当通过文件、网络来读取序列化后的对象时,必须按照实际写入的顺序读取。
- 单例类序列化,需要重写readResolve()方法;否则会破坏单例原则。
- 同一对象序列化多次,只有第一次序列化为二进制流,以后都只是保存序列化编号,不会重复序列化。
- 建议所有可序列化的类加上serialVersionUID 版本号,方便项目升级。