【深度解析】序列化与反序列化 探析
或许很多同学像本人一样,刚开始接触 序列化
这个概念时,觉得也没什么
但是随着我们了解的知识点越来越多,直到做一些Web开发时,才发现 好多POJO都需要实现Serializable接口
在本人之前的博文《详解 序列化流 与 反序列化流》中,曾讲到过Java中的有关 序列化
与 反序列化
的知识点
那么,在本篇博文中,本人就来通过一个小demo,来讲解下 序列号 的本质:
举个栗子(Demo):
首先,本人来给出一个实现了Serializable接口的POJO类:
序列化的pojo:
package edu.youzg.test.about_serializable;
import java.io.Serializable;
/**
* @Author: Youzg
* @CreateTime: 2020-12-20 10:21
* @Description: 带你深究Java的本质!
*/
public class Fan implements Serializable {
private static final long serialVersionUID = 3439052454193760044L;
private String name;
private Integer age;
private int likeNum;
public Fan() {
}
public Fan(String name, Integer age, int likeNum) {
this.name = name;
this.age = age;
this.likeNum = likeNum;
}
public static long getSerialVersionUID() {
return serialVersionUID;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
public int getLikeNum() {
return likeNum;
}
public void setLikeNum(int likeNum) {
this.likeNum = likeNum;
}
@Override
public String toString() {
return "Fan{" +
"name='" + name + '\'' +
", age=" + age +
", likeNum=" + likeNum +
'}';
}
}
友情提示:
请牢记当前pojo的
serialVersionUID
:
3439052454193760044L
(其实在下面的案例中,要修改也就只会修改最后一位)
那么,本人就先通过之前文章《详解 序列化流 与 反序列化流》中所讲到的 ObjectOutputStream类
,将目标对象序列化,并将序列化后的信息转存到文件中:
序列化 pojo对象:
package edu.youzg.test.about_serializable;
import edu.youzg.network_transmission.section.FileSectionInfo;
import java.io.*;
/**
* @Author: Youzg
* @CreateTime: 2020-12-20 10:25
* @Description: 带你深究Java的本质!
*/
public class GenerateFileTest {
public static void main(String[] args) {
try {
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("./prettyGril.txt"));
Fan aFan = new Fan("prettyGril", 16, 666);
oos.writeObject(aFan);
} catch (Exception e) {
// TODO: handle exception
}
}
}
读取并反序列化 pojo对象:
package edu.youzg.test.about_serializable;
import edu.youzg.network_transmission.section.FileSectionInfo;
import java.io.*;
/**
* @Author: Youzg
* @CreateTime: 2020-12-20 10:25
* @Description: 带你深究Java的本质!
*/
public class GenerateFileTest {
public static void main(String[] args) {
try {
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("./prettyGril.txt"));
System.out.println("0");
Fan aFan = (Fan) ois.readObject();
System.out.println("1");
System.out.println(aFan.toString());
System.out.println(aFan == null);
System.out.println(aFan.toString().equals(""));
} catch (Exception e) {
e.printStackTrace();
}
}
}
可以看到,运行结果如下:
由于在之前的博文《详解 序列化流 与 反序列化流》中,本人已经演示过 反序列化时不加序列号 的情况了
那么,在本文中,本人仅来展示 反序列化时序列号不一致 的情况:
反序列化时序列号不一致:
修改 序列号 为 3439052454193760045L
继续运行上文中的 反序列化程序:
由于所展示空间有限,本人就将 控制台内容 粘贴到下方:
0
java.io.InvalidClassException: edu.youzg.test.about_serializable.Fan; local class incompatible: stream classdesc serialVersionUID = 3439052454193760044, local class serialVersionUID = 3439052454193760045
at java.io.ObjectStreamClass.initNonProxy(ObjectStreamClass.java:616)
at java.io.ObjectInputStream.readNonProxyDesc(ObjectInputStream.java:1843)
at java.io.ObjectInputStream.readClassDesc(ObjectInputStream.java:1713)
at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:2000)
at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1535)
at java.io.ObjectInputStream.readObject(ObjectInputStream.java:422)
at edu.youzg.test.about_serializable.GenerateFileTest.main(GenerateFileTest.java:28)
可以看到:
由于 反序列化时序列号不一致,反序列化失败了!
那么,反序列化时不加序列号
和 反序列化时序列号不一致
都会导致 反序列化失败,
这是为什么呢?
那么,接下来,正片开始!
首先,我们来看看序列化后的 序列化文件内容:
序列化 文件内容:
IDEA打开:
???WTF
这都什么乱七八糟的?
二话不说,直接用 其它编辑器 查看其 字节码:
字节码内容:
还是一团乱麻!!!
别急嘛,我们再来看看之前的序列号
:
那么,我们将这个序列号拿计算器转换下进制
:
进制转换:
当然,我们现在只需要关心 十六进制
即可:
2FB9 F7FC 7827 872C
在字节码文件中查找,就会找到相应的 字节码信息
:
序列化的字节码文件中,包含了 被序列化的pojo对象 的 全部信息,
包括其 序列号
当我们反序列化时,就会拿自己的pojo对象的序列号与其对比
若是 不存在序列号(没有实现Serializable接口),就会序列化失败!
如此一来,相信就能彻底解释清楚 序列号 的 重要作用 的 原因 了!
那么,为什么对象序列化之后,为什么生成的数据格式是上图所示呢?
底层实现:
请观看本人博文 —— 《【源码剖析】序列化 底层实现原理》