36.Java序列化与反序列化是什么
- 序列化就是把Java对象转换成字节流(二进制)。
- 把对象保存到本地文件或网络传输。因为Java对象在JVM的堆内存中,JVM堆不存在了,对象也就不在了。
- 反序列化就是把字节流转换为对象
- 从文件或者网络里获取字节流,通过反序列化就可以重建对象
为什么需要序列化与反序列化?
进行持久化或者网络传输时需要序列化与反序列化。
跨平台和跨语言通信,序列化为二进制文件,可以在不同平台和语言解析。
Java对象序列化不仅仅保留一个对象的数据,也会递归保留对象引用的每个对象的数据
序列化实现的方式有哪些?
-
实现serializable接口或者Externalizable接口
-
Serializable接口
-
特点:
- 简单易用:只需实现接口即可。
- 默认行为:自动序列化所有非
transient
和非静态字段。 - 版本控制:通过
serialVersionUID
控制类版本兼容性。
-
缺点:
- 性能较差:生成的字节流较大,效率较低。
- 跨语言不兼容:只能用于 Java 系统内部。
- 安全性问题:反序列化不可信数据可能导致漏洞。
-
public class Person implements Serializable {private static final long serialVersionUID = 1L;private String name;private int age;// 构造方法、getter/setter }// 序列化 ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("person.ser")); oos.writeObject(new Person("Alice", 30));// 反序列化 ObjectInputStream ois = new ObjectInputStream(new FileInputStream("person.ser")); Person person = (Person) ois.readObject();
-
-
自定义序列化(
Externalizable
接口)-
特点:
- 完全控制序列化逻辑:可选择性地序列化字段。
- 更灵活:适合需要优化存储或传输效率的场景。
-
缺点:
- 开发成本高:需要手动编写序列化/反序列化逻辑。
-
public class Person implements Externalizable {private String name;private int age;@Overridepublic void writeExternal(ObjectOutput out) throws IOException {out.writeUTF(name);out.writeInt(age);}@Overridepublic void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {name = in.readUTF();age = in.readInt();} }
-
-
什么是serialVersionUID
用来表示类的不同版本的兼容性。
来验证版本是否一致,JVM在反序列化时,拿到传过来的字节码文件,用字节码文件的UID去和本地的类文件的UID去比对,如果一致就会进行反序列化。
为什么还要显示指定serialVersionUID的值
- 如果不显示指定,JVM就会在反序列化时新生成一个UID去和本地类的UID去对比
- 如果显示指定了,JVM任然会去生成UID,但是UID值是我们显示指定的值,会去和本地的显示指定的UID去对比,这样旧和新的UID都是一致的,是我们显示指定的。
- 在实际开发中,编写的类会一直不断迭代,如果修改了类,UID就会改变,所以我们显示指定一个UID,保持UID一致。
serialVersionUID什么时候修改?
序列化类新增属性时,不要修改UID,避免反序列化失败。如果完全不兼容升级,避免反序列化混乱,修改UID。
Java 序列化中如果有些字段不想进行序列化,怎么办?
对于不想进行序列化的变量,使用 transient 关键字修饰。transient只能修饰变量,不能修饰类和方法。反序列化后,transient修饰的值会设为初始值,如int类型就会为0,对象类型就会为null。
静态变量会被序列化吗?
sient 关键字修饰。transient只能修饰变量,不能修饰类和方法。反序列化后,transient修饰的值会设为初始值,如int类型就会为0,对象类型就会为null。
静态变量会被序列化吗?
不会,因为序列化是针对对象而言的,而静态变量会随着类的加载而加载,优先于对象存在。serialVersionUID也被static修饰, 为什么serialVersionUID会被序列化?其实serialVersionUID属性并没有被序列化, JVM在序列化对象时会自动生成一个serialVersionUID, 然后将我们显示指定的serialVersionUID属性值赋给自动生成的serialVersionUID。