【深度解析】序列化与反序列化 探析

shadowLogo

或许很多同学像本人一样,刚开始接触 序列化 这个概念时,觉得也没什么
但是随着我们了解的知识点越来越多,直到做一些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接口),就会序列化失败!

如此一来,相信就能彻底解释清楚 序列号 的 重要作用原因 了!
boki


那么,为什么对象序列化之后,为什么生成的数据格式是上图所示呢?

底层实现:

请观看本人博文 —— 《【源码剖析】序列化 底层实现原理》

posted @ 2020-12-20 13:47  在下右转,有何贵干  阅读(248)  评论(0编辑  收藏  举报