什么是 Java 序列化?
Java序列化指的是一种将数据转换成字节形式以便Java系统内部使用的对象或数据可以在外部Java系统中使用的技术,以及一种将转换后的数据转换回对象的技术(反序列化)。
也称为将系统地驻留在JVM的运行时数据区(堆或栈区)的对象数据转换成字节形式的技术,以及将序列化的字节数据转换成对象并驻留在JVM中的形式。
实现可序列化
public interface Serializable() {
}
当我们创建的类可以读取或写入文件,或者从另一个服务器发送和接收时,必须实现这个接口(Serializable)。
- 将创建的对象保存为文件时
- 读取存储对象时
- 当接收到另一个服务器创建的对象时
简而言之,实现 Serializable 接口允许 JVM 存储对象或将其传输到另一个服务器。
不可序列化的
在正常情况下,序列化是不可能的。
但是,如果Serializable实现的类是继承的,则有可能。
什么是瞬态?
一般来说,一个类的所有成员变量都是可序列化的。
但是,如果您出于安全原因或其他原因要排除部分成员变量,transient则可以使用:
public class User implements Serializable {
private String id;
private transient String password;
private String email;
//....
}
如果您有另一个对象作为成员变量
除了 int、long 和 String 等基本数据类型外,其他对象也经常用作成员变量。
public class User implements Serializable {
private String id;
private transient String password;
private String email;
ItemInfo itemInfo;
Calendar regDate;
//....
}
在上面的代码ItemInfo中,如果类中没有实现接口Calendar的类,则会引发异常。 换句话说,当有一个类没有实现成员变量类时,序列化是不可能的。Serializablejava.io.InvalidClassException
Serializable
serialVersionUID
序列化时,内部会自动SerialVersionUID生成一个唯一的编号来管理类的版本。
这UID在序列化和反序列化时起着重要作用。
由于是在检查该值是否正确后进行处理,SerialVersionUID如果不匹配则抛出异常java.io.InvalidClassException。
- serialVersionUID不是必需的值。
- 兼容类serialVersionUID具有固定值。
- serialVersionUID如果未声明,则使用该类的默认哈希值。
除非有特殊问题,Java序列化版本serialVersionUID值应该由开发者自己管理。
Java序列化的优点
Java 序列化针对Java 系统开发进行了优化。
即便是数据结构复杂的对象,只要遵守序列化的基本条件,也不需要太多的工作就可以序列化。
特别是,由于数据类型是自动匹配的,所以你不必太担心相关的部分。
当以这种方式反序列化时,它可以像现有对象一样立即使用。
Java序列化的缺点
除非有特殊问题,否则 Java 序列化版本 ( serialVersionUID) 值应由开发人员管理。应避免更改
要反序列化的类的成员变量类型。Java 反序列化是类型严格的。(即使稍后更改类型,您也必须处理所有异常)
对于要长时间存储在外部(DB、缓存服务器等)的信息,应避免使用 Java 序列化。
(要反序列化的类长期存在于外部不知道何时改变的环境中→我的系统不知道何时可能发生异常)
对于开发人员无法直接控制的类的对象,应避免序列化。(一般是框架、库等提供的类的对象)这样的对象通常serialVersionUID都有,所以为了方便,将其序列化并存储在DB中,但是这部分出现了问题。
- 版本控制时框架或库serialVersionUID发生更改
- 测试时一切正常,但体现在操作上
与此相关的一个示例是SecurityContextImplSpring Security 类。
serialVersionUID由于该值是 Spring Security 的版本值,因此据说每当版本更改时都会对其进行处理。
结论
不建议对频繁更改的类的对象使用 Java 序列化。
因为它很容易发生变化,所以更容易发生意外的异常。
特别是,建议默认异常处理,例如不执行反序列化时。