java 序列化 原理解析

序列化相關文章:
* Java 序列化 之 Serializable
* Java 序列化之 Externalizable
* Java 序列化 之 單例模式

閱讀本文章之前,務必要閱讀上面的三篇文章。
這篇文章是圍繞上面三篇文章的原理進行剖析的。
因爲 ObjectInputStream 和 ObjectOutputStream 類比較複雜,這裏只解析跟上面三篇文章相關的內容。

java 序列化示例

public class Test{
    public static void main(String[] args) throws Exception {
        File file = new File("d:\\a.user");
        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(file));
        oos.writeObject(User.getInstance());
        oos.close();

        ObjectInputStream ois = new ObjectInputStream(new FileInputStream(file));
        User user = (User) ois.readObject();
        ois.close();
        System.out.println(user);

        if(user==User.getInstance()){
            System.out.println("同一個實例");
        }else{
            System.out.println("不同的實例");
        }
    }
}

通過該示例,我們知道 Java 序列化是由 ObjectInputStream 和 ObjectOutputStream 兩個類實現的,下面我們就通過這兩個類來揭開 Java 序列化的神祕面紗。

ObjectOutputStream 原理解析

writeObject 方法


1、通過 enableOverride 判斷是否執行 writeObjectOverride() 方法。
2、調用writeObject() 方法。

writeObjectOverride() 方法


通過源碼發現這個方法是個空方法,這是搞什麼鬼?
仔細分析後可以發現 writeObject 方法是final 類型的,也就是子類無法重寫的,通過 向子類暴露 writeObjectOverride 方法來達到重寫的目的。

writeObject0方法


在 writeObject0() 方法中,跳過一些檢查操作,直接分析最核心的這段代碼。
1、 如果該對象是String、數組、枚舉類型的,調用響應的方法進行寫入。

在這裏String和 Enum 類型不實現 Serializable 也可以序列化的,但String 類中還是實現了 Serializable 接口,告訴大家,該類可以序列化的。

2、如果對象是 Serializable 的,則調用 writeOrdinaryObject() 方法,該方法是序列化的核心方法。

在這裏我們終於看到 Serializable的作用了。因爲Serializable中沒有定義方法,只是起到標識作用,該標識作用就在這提現。

writeOrdinaryObject 方法


1、檢查是否可以序列化
2、寫入類型
3、寫 class 的描述信息
4、判斷是 該對象 否實現了 Externalizable 接口
* 如果實現了則調用 writeExternalData 方法。
* 如果沒有實現則調用 writeSerialData 方法。

這裏,我們可以看到,如果實現了 Externalizable 接口,會優先執行 Externalizable 接口的實現的方法,而默認的序列化方法不會執行。
這裏也解釋了上一篇文章中Java 序列化之 Externalizable 示例三 的原因。

writeExternalData 方法

實現 Externalizable 序列化接口

通過該方法可以看到,在這裏會調用我們自己定義的 WriteExternal() 方法。

writeSerialData 方法

實現 Serializable 序列化接口

* 1、判斷該類是否定義了 writeObject() 方法,如果定義了,則通過反射調用該對象的 writeObject() 方法,執行我們自己定義的序列化規則。
* 2、沒有定義writeObject() 方法,則調用 defaultWriteFields() 方法執行默認的序列化規則。
我們平常在重寫 writeObject() 方法的時候一般也會先調用 defaultWriteFields() 方法的,然後在寫上其它特殊的序列化。

ObjectInputStream 原理解析

ObjectInputStream 原理其實同 ObjectOutputStream 差不多,明白 ObjectInputStream 後再看 ObjectoutputStream 就很 easy 了。

readObject 方法


1、提供給子類進行重寫反序列化功能(readObject 方法是final的,但提供 readObjectOverride() 給子類去覆蓋實現)
2、反序列化調用 readObject0() 方法去實現。

readObject0 方法


該方法中提供了好多類型的反序列化方法支持。
但是我們這裏只關注 Object類型的反序列化。這裏調用的是 readOrdinaryObject() 。

readOrdinaryObject 方法


1、判斷該類是否實現了 Externalizable 接口,如果實現了Externalizable 接口,就執行readExternalData () 方法
2、否則,執行 readSerialData() 方法,使用默認的 Serializable 接口的反序列化方法執行發序列化。

3、判斷該類是否定義了 readResolve() 方法,如果定義了 readResolveMethod() 方法,則執行用戶定義的 readResolve() 方法。該方法的作用,請參考文章: Java 序列化 之 單例模式

readExternalData 方法


調用用戶實現的 readExternal() 方法實現對象的反序列化。

readSerialData 方法


判斷用戶是否實現了 readObject() 方法,如果實現,則執行用戶自定義的發序列化方法。

否則執行ObjectInputStream中默認的序列化方法 defaultReadFields();

通過ObjectOutputStream 類的簡單分析,我們就可以瞭解到 Serializable 和 Externalizable 的原理。


想了解更多精彩內容請關注我的公衆號

本人簡書blog地址:http://www.jianshu.com/u/1f0067e24ff8    
點擊這裏快速進入簡書
GIT地址:http://git.oschina.net/brucekankan/
點擊這裏快速進入GIT

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章