Java序列化機制原理


Java序列化就是將一個對象轉化為一個二進制表示的字節數組,通過保存或則轉移這些二進制數組達到持久化的目的。要實現序列化,需要實現java.io.Serializable接口。反序列化是和序列化相反的過程,就是把二進制數組轉化為對象的過程。在反序列化的時候,必須有原始類的模板才能將對象還原。從這個過程我們可以猜測到,序列化過程並不想class文件那樣保存類的完整的結構信息。下面我們以一個簡單的例子來看一下,序列化的時候都保存了哪些信息。代碼如下:

package com.ysl;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
import java.io.Serializable;

public class SerializableTest implements Serializable{

    private static final long serialVersionUID = -1L;
    public int num = 2018;

    public static void main(String[] args){
        try {
            FileOutputStream fos = new FileOutputStream("serializable");
            ObjectOutputStream oos = new ObjectOutputStream(fos);
            SerializableTest test = new SerializableTest();
            oos.writeObject(test);
            oos.flush();
            oos.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

序列化后的二進制字節數據如下:

aced 0005 7372 0018 636f 6d2e 7973 6c2e
5365 7269 616c 697a 6162 6c65 5465 7374
ffff ffff ffff ffff 0200 0149 0003 6e75
6d78 7000 0007 e2

上述的內容分為一下幾個部分:

第一部分是序列化文件頭

  • AC ED :STREAM_MAGIC聲明使用了序列化協議
  • 00 05 :STREAM_VERSION序列化協議版本
  • 73 :TC_OBJECT聲明這是一個新的對象

第二部分是序列化的類的描述,在這里是SerializableTest

  • 72 :TC_CLASSDESC聲明這里開始一個新的class
  • 00 18:class名字的長度是24個字節
  • 636f 6d2e 7973 6c2e 5365 7269 616c 697a 6162 6c65 5465 7374:SerializableTest的完整類名
  • ffff ffff ffff ffff:serialVersionUID,序列化ID,如果沒有指定,則會由算法隨機生成一個8字節的ID
  • 02 :標記號,聲明該類支持序列化
  • 00 01:該類所包含的域的個數為1

第三部分是對象中各個屬性的描述

  • 49:域類型,49代表I,也就是int類型
  • 00 03:域名字的長度為3
  • 6e 75 6d:num屬性的名稱

第四部分為對象的父類信息描述

SerializableTest沒有父類,如果有,和第二部分的描述相同

  • 78 :TC_ENDBLOCKDATA,對象塊的結束標志
  • 70:TC_NUL:說明沒有其他超類的標志

第五部分為對象屬性的實際值

如果屬性是一個對象,那么這里還將序列化這個對象,規則和第二部分一樣

  • 00 0007 e2:數值2018

雖然Java的序列化能夠保證對象狀態的持久保存,但是遇到一些對象結構復雜的情況還是比較難處理的,下面是對一些復雜情況的總結:

  • 當父類實現了Serializable接口的時候,所有的子類都能序列化
  • 子類實現了Serializable接口,父類沒有,父類中的屬性不能被序列化(不報錯,但是數據會丟失)
  • 如果序列化的屬性是對象,對象必須也能序列化,否則會報錯
  • 反序列化的時候,如果對象的屬性有修改或則刪減,修改的部分屬性會丟失,但是不會報錯
  • 在反序列化的時候serialVersionUID被修改的話,會反序列化失敗
  • 在存Java環境下使用Java的序列化機制會支持的很好,但是在多語言環境下需要考慮別的序列化機制,比如xml,json,或則protobuf


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM