一、带着问题来看
- 什么是序列化和反序列化
- 实现序列化和反序列化为什么要实现Serializable接口?
- 为什么还要显示指定serialVersionUID的值?
二、序列化的含义与使用场景
- 序列化:把对象转换为字节序列的过程称为对象的序列化.
- 反序列化:把字节序列恢复为对象的过程称为对象的反序列化.
当我们只在本地JVM里运行下Java实例, 这个时候是不需要什么序列化和反序列化的, 但当我们需要将内存中的对象持久化到磁盘, 数据库中时, 当我们需要与浏览器进行交互时, 当我们需要实现RPC时, 这个时候就需要序列化和反序列化了。
举个栗子:把一个没有实现序列化的User类写到文件中
疑问:为什么类没有实现序列化也可以持久化到数据库中?
答:实际上我们并不是将整个对象持久化到数据库中, 而是将对象中的属性持久化到数据库中, 而这些属性都是实现了Serializable接口的基本属性.
对于JSON格式实际上就是将一个对象转化为字符串, 所以服务器与浏览器交互时的数据格式其实是字符串,而字符串其实也是实现了序列化的。
三、实现序列化和反序列化为什么要实现Serializable接口?
在Java中实现了Serializable接口后, JVM会在底层帮我们实现序列化和反序列化, 如果我们不实现Serializable接口, 那自己去写一套序列化和反序列化代码也行
四、为什么还要显示指定serialVersionUID的值?
如果不显示指定serialVersionUID, JVM在序列化时会根据属性自动生成一个serialVersionUID, 然后与属性一起序列化, 再进行持久化或网络传输. 在反序列化时, JVM会再根据属性自动生成一个新版serialVersionUID, 然后将这个新版serialVersionUID与序列化时生成的旧版serialVersionUID进行比较, 如果相同则反序列化成功, 否则报错.
如果显示指定了serialVersionUID, JVM在序列化和反序列化时仍然都会生成一个serialVersionUID, 但值为我们显示指定的值, 这样在反序列化时新旧版本的serialVersionUID就一致了.
五、总结
- 在Java中,只要一个类实现了
java.io.Serializable
接口,那么它就可以被序列化。 - 通过
ObjectOutputStream
和ObjectInputStream
对对象进行序列化及反序列化 - 虚拟机是否允许反序列化,不仅取决于类路径和功能代码是否一致,一个非常重要的一点是两个类的序列化 ID 是否一致(就是
private static final long serialVersionUID
) - 序列化并不保存静态变量。
- 要想将父类对象也序列化,就需要让父类也实现
Serializable
接口。 - Transient 关键字的作用是控制变量的序列化,在变量声明前加上该关键字,可以阻止该变量被序列化到文件中,在被反序列化后,transient 变量的值被设为初始值,如 int 型的是 0,对象型的是 null。
- 服务器端给客户端发送序列化对象数据,对象中有一些数据是敏感的,比如密码字符串等,希望对该密码字段在序列化时,进行加密,而客户端如果拥有解密的密钥,只有在客户端进行反序列化时,才可以对密码进行读取,这样可以一定程度保证序列化对象的数据安全
所有需要网络传输的对象都需要实现序列化接口,通过建议所有的javaBean都实现Serializable接口