用遊戲來講序列化與反序列化機制

2022-06-12 15:00:33

一、寫在最前

想象一下,你剛開始玩一個遊戲,一進遊戲,首先系統提示你需要建立一個角色。

新建角色物件:姓名(宇宙第一無敵厲害)誰會取這樣的名字哈哈哈、性別、門派、等級......

建完角色之後,來到新手村,對於一個心懷大俠夢的有志青年當然不能被困在這小小的新手村了,所以你需要去刷boss攢經驗升級。

boss物件:血量、等級、擁有技能......

就這樣,經過不懈努力,你終於達到了能出新手村的等級。這時候,夜深了,你媽氣急敗壞叫你關電腦睡覺。大家都知道,建立的物件是儲存在記憶體中的,記憶體中的資料斷電即失。難道剛要出新手村,大俠夢就破滅了?怎麼辦呢?

二、大俠夢持續輸出——序列化

為了不讓無數青年的大俠夢關機即碎,序列化技術出現了,在遊戲中的體現就是存檔。即,在退出遊戲的時候,點選存檔按鈕,這時候,你遊戲角色的等級,裝備等都會被儲存在儲存媒體中(硬碟等)。這時候,就算你關機了,下次再次登入遊戲,還是你關機時儲存的角色狀態。

總結:序列化就是將記憶體中的物件資料儲存到儲存媒體中。

三、小爺我又回來了——反序列化

當天晚上,你在你媽的壓迫下無奈關機睡覺了。第二天起來你迫不及待開啟遊戲準備再次大幹一場,可是遊戲角色已經被序列化到硬碟中,怎麼取出來呢?這時候,反序列化技術就出現了。就是把你存在硬碟上的資料還原成原來的遊戲物件,該是多少級還是多少級,該是啥裝備就是啥裝備。

總結:反序列化就是將儲存在媒體中的物件還原成記憶體中物件。

序列化與反序列化擴充套件:

對於序列化來講,不單單是作為將記憶體中的資料儲存到媒體中,其網路傳輸也是一大作用。

你想想,玩遊戲當然是大家一起玩才好了。每個遊戲玩家在遊戲世界中都可以進行溝通交流,當你刷boss的時候,爆到了一把一刀999的屠龍寶刀。這時候,你可以選擇高價賣給遊戲的其他土豪玩家。這時候,你不可能直接通過網線把這個給人家,而是通過序列化的方法,把這把屠龍刀傳輸給買家,買家在接收到這個資料之後,再通過反序列化將這把寶刀還原。

即,序列化的作用:

儲存記憶體中的物件、進行網路傳輸。

四、序列化機制探究

上文說到,序列化可以進行網路傳輸,說到網路傳輸,那麼I/O就不能陌生了,I/O傳輸支援的資料格式是位元組陣列。即,要想進行網路傳輸,就是將傳輸的物件轉換成位元組陣列。但是,我們不能盲目隨便轉換成位元組陣列,因為你後面還需要將物件進行還原。也就是說,在進行轉換的時候你要指定一個規則(序列化),在將物件轉換成位元組陣列的時候按照這個規則進行轉換。那個將物件進行還原的時候,按照規則(反序列化)進行還原。你不能將一個人偶拆了之後,裝的時候,把手裝成腳。

即,序列化機制:

將物件轉換成位元組陣列的時候的轉換規則,這種轉換規則就是序列化機制。

五、序列化的種類

原生的JDK

JDK自帶了序列化方法,只需要實現了Serializable介面的類,就可以通過ObjectOutputStream類將物件變成byte[]位元組陣列。

弊端:只能java自己玩。

程式碼範例:

/**
 * @ClassName Student
 * @Description Student類物件
 * @Author LH
 * @Date 2022/6/12 10:32
 */
@Data
public class Student implements Serializable {
    private String id;
    private String name;
    private int age;
}
/**
 * @ClassName JDKSerialize
 * @Description JDK序列化介面測試
 * @Author LH
 * @Date 2022/6/12 10:41
 */
public class JDKSerialize {

    /**
     *  物件序列化
     * @param  student 學生物件
     * @throws IOException 丟擲io異常
     */
    public static void serializeStudent(Student student) throws IOException {
        ObjectOutputStream oo = new ObjectOutputStream(new ObjectOutputStream(Files.newOutputStream(new File("E:/java/workplace/study/student.txt").toPath())));
        oo.writeObject(student);
        oo.close();
    }

    /**
     * 物件反序列化
     * @param path 反序列化檔案路徑
     * @return Student 還原的學生物件
     * @throws IOException 丟擲io異常
     * @throws ClassNotFoundException 找不到檔案異常
     */
    public static Student deSerializeStudent(String path) throws IOException, ClassNotFoundException {
        ObjectInputStream ois = new ObjectInputStream(new ObjectInputStream(Files.newInputStream(new File(path).toPath())));
        Student student = (Student) ois.readObject();
        ois.close();
        return student;
    }

    public static void main(String[] args) {
        // 建立一個student物件
        Student student = new Student();
        student.setId("1");
        student.setName("LH");
        student.setAge(17);

        try {
            // 序列化student物件
            JDKSerialize.serializeStudent(student);
            // student物件飯序列化
            String path = "E:/java/workplace/study/student.txt";
            Student deSerializeStudent = JDKSerialize.deSerializeStudent(path);
            System.out.println("student id:" + deSerializeStudent.getId() + "student age:" + deSerializeStudent.getAge() + "student name:" + deSerializeStudent.getName());
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

ProtoBuf

谷歌推出,一種語言無關、平臺無關、可延伸的序列化結構資料的方法,可用於通訊協定、資料儲存等。序列化後體積小,一般用於對傳輸效能有較高要求的系統。

瞭解不是很多,後面工作用到的話再來進行擴充套件。

JSON

在系統之間進行互動的時候很常用。

JSON 序列化方式生成的是一串有規則的字串,可讀性強。是有規則的字串,不跟任何程式語言繫結,天然上就具備了跨平臺。

弊端:體積大。

常見的工具有:

fastJSONJacksonGson 等。工作中比較常用的就是阿里的fastJSON,使用起來也很簡單,直接呼叫轉換的api即可,瞭解更多可以去官網看看。

各種序列化手段都有不同的特性,看你的業務再去選型。

序列化如何選擇

主要考慮三點:

  • 選擇的序列化手段是否需要跨平臺

  • 選擇的序列化手段的速度要求

  • 選擇的序列化手段的體積要求