參考: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中的數組容量基本上都會比實際的元素的數大, 爲了避免序列化沒有元素的數組而重寫.