JDK序列化原理總結

參考:https://juejin.im/entry/5bf622436fb9a04a0b21cbe7

JDK序列化方式中,使用ObjectInputStream#readObject進行反序列化,使用ObjectInputStream#writeObject進行序列化,反序列化稍微複雜點,朋友們可以結合文字看源碼

ObjectInputStream#readObject:

A 判斷子類是否重寫了readObject方法。因爲readObject是final修飾,所以實質上重寫的是readObjectOveride方法,如果重寫了,則直接執行子類重寫的readObjectOverride方法。

B 如果沒有,則指向readObject0,readObject0就是底層執行反序列化的主要方法:

1 選擇反序列化方法

2 如果是反序列化對象,則會執行readOrdinaryObject方法:

1 反序列化創建了新的對象,這就是反序列化可以破壞單例的原因;

2 判斷序列化方式,可以看到實現Externalizable接口的方式優先級要高於實現Serializable接口的方式,如果使		用的是Serializable方式,則會執行readSerialData方法:

		1 判斷被序列化的類中是否包含readObject方法;(hasReadObjectMethod)

		2 如果包含,就執行被序列化類中的readObject方法;(HashMap、ArrayList重寫了)

		3 如果不包含, 執行ObjectInputStream默認的defaultReadFields方法。

3 判斷被序列化的類是否包含readResolve方法,如果包含,則執行readResolve方法,並使用該方法返回的對		象替換之前創建的obj(代碼obj=rep進行的替換,解決單例序列化的問題)。

ObjectInputStream#writeObject原理類似,對反序列化的數據按照順序讀取而已:

A 判斷子類是否重寫了writeObject方法。因爲writeObject是final修飾,所以實質上重寫的是writeObjectOveride方法,如果重寫了,則直接執行子類重寫的writeObjectOverride方法。

B 如果沒有,則指向writeObject0,writeObject0就是底層執行序列化的主要方法:

1 選擇序列化方法

2 如果是序列化對象,則會執行writeOrdinaryObject方法:

1 判斷序列化方式,可以看到實現Externalizable接口的方式優先級要高於實現Serializable接口的方式,如果使		用的是Serializable方式,則會執行writeSerialData方法:

		1 判斷被序列化的類中是否包含writeObject方法;(hasWriteObjectMethod)

		2 如果包含,就執行被序列化類中的writeObject方法;(HashMap、ArrayList重寫了)

		3 如果不包含, 執行ObjectOutStream默認的defaultWriteFields方法。

HashMap如果不重寫writeObject和readObject:假設機器A要傳輸一個HashMap到機器B,且AB對於hashCode()的實現不一致,那麼在A將HashMap整個序列化到B後,Entry上元素的位置在兩個機器是一樣的,但是因爲hashCode()不一樣,如果此時B要獲取key=”pdc“這個元素,這個元素在A上存儲的時候,位置爲0,而到了B,通過hashCode()和HashMap的get方法得到的位置卻爲1,那麼得到的就不是key=”pdc“了,而是其他key。

所以爲了一致性,直接重寫writeObject和readObject,A直接傳輸key和value,讓B自己根據自己的hashCode()重新put進Entry,如key=”pdc“,put的位置爲1,這樣AB兩臺機器上的HashMap雖然Entry上元素的位置不一樣,但是兩臺機器並不互相影響,而此時B通過hashCode()和HashMap的get方法得到key=”pdc“的位置爲1,這樣就一致了

ArrayList則是因爲在ArrayList中的數組容量基本上都會比實際的元素的數大, 爲了避免序列化沒有元素的數組而重寫.

發佈了232 篇原創文章 · 獲贊 260 · 訪問量 2萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章