1. 程式人生 > 實用技巧 >【深度解析】序列化與反序列化 探析

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

或許很多同學像本人一樣,剛開始接觸 序列化 這個概念時,覺得也沒什麼
但是隨著我們瞭解的知識點越來越多,直到做一些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介面),就會序列化失敗!

如此一來,相信就能徹底解釋清楚 序列號 的 重要作用原因 了!