1.什麼是Java序列化與反序列化? java
序列化:將java對象轉換爲字節序列的過程叫作序列化及Serialization(序列化)是一種將對象以一連串的字節描述的過程;redis
反序列化:將字節對象轉換爲java對象的過程叫作反序列化及是一種將這些字節重建成一個對象的過程。Java序列化API提供一種處理對象序列化的標準機制。spring
序列化:將對象變爲--------------------------->文件中數據數據庫
反序列化:將文件中的數據------------------------>轉換爲對象json
2.爲何須要Java序列化與反序列化?緩存
(1)、存儲網絡
在java系統運行過程當中,java對象只存在於堆棧中,可是一旦系統中止運行了,或者某次交互回話結束後,這些java對象也不存在了,架構
想要再次得到java對象,則須要從一些存儲設備中讀取數據,而且還原爲原先的java對象,系統才能夠再次正常運行。框架
這裏存儲設備,能夠是文件,緩存(好比EhCache,MemCache,redis等等),甚至是數據庫中,均可以,保存這些對象的字節流,等待java對象再次復活!jvm
(2)、傳輸&交換
分佈式系統中,系統之間交互,好比經過java原生的RMI遠程調用,返回的字節流反序列化爲java對象,才能在jvm裏運行。
Java中,一切都是對象,在分佈式環境中常常須要將Object從這一端網絡或設備傳遞到另外一端。 這就須要有一種能夠在兩端傳輸數據的協議。Java序列化機制能夠作到。
或者當下經常使用的分佈式架構,http+json返回的json數據,也是須要反序列化爲java對象,只是用的方法和jdk原生不一樣罷了,
以及新的分佈式架構,thrift,dubbo等,返回的數據是字節流的形式,也是須要反序列化。
3.怎麼Java序列化與反序列化?
java JDK自帶的序列化工具備
java.io.ObjectOutputStream表明對象輸出流,它的writeObject(Object obj)方法可對參數指定的obj對象進行序列化,把獲得的字節序列寫到一個目標輸出流中。
java.io.ObjectInputStream表明對象輸入流,它的readObject()方法從一個源輸入流中讀取字節序列,再把它們反序列化爲一個對象,並將其返回。
只有實現了Serializable和Externalizable接口的類的對象才能被序列化。Externalizable接口繼承自 Serializable接口,實現Externalizable接口的類徹底由自身來控制序列化的行爲,而僅實現Serializable接口的類能夠 採用默認的序列化方式 。
對象序列化通常包括以下步驟:
1) 建立一個對象輸出流,它能夠包裝一個其餘類型的目標輸出流,如文件輸出流;
2) 經過對象輸出流的writeObject()方法寫對象。
對象反序列化的步驟以下:
1) 建立一個對象輸入流,它能夠包裝一個其餘類型的源輸入流,如文件輸入流;
2) 經過對象輸入流的readObject()方法讀取對象
特殊說明下:實現Serializable接口的java對象,有一個serialVersionUID,serialVersionUID: 字面意思上是序列化的版本號,凡是實現Serializable接口的類都有一個表示序列化版本標識符的靜態變量,
同一個java對象只要序列化ID相同,屬性相同,那麼反序列化會正常的執行
同一個java對象,若是序列化ID不一樣,屬性相同,反序列化都不會成功
由於默認的JDK序列化與反序列化方法要求必須實現Serializable接口,而且序列化ID相同,這時jvm才承認字節流是能夠反序列化的,
4.有沒有造好的輪子?
java序列化的框架目前也很多,具體實現沒來得及一一研究,有基於json反序列化的(GSON,Jackson),有基於字節流實現的(protobuf),以及基於xml等等
5.應用實例:
spring-data-redis 存數據的時候要序列化,取數據的時候要反序列化
當須要把一個對象以hash存儲在redis中時候,我是很輕鬆愉快的寫完了。
而後寫測試用例,相應的實體bean屬性存值竟然爲null,debug屢次,發現仍是null值。
因而找到個人bean類,將其 implements Serializable 感受這下應該 test success 了,
可可是,還特麼是null。
個人bean類已經實現了序列化接口,安靜了片刻,去看bean的父類fatherbean,父類fatherbean 並無implements Serializable,而後果斷將父類fatherbean implements Serializable, 再一測,這時真正的 test success 了
那麼書上是這麼說的。。
當父類繼承serializable 接口時,全部的子類均可以被序列化
子類實現了serializable接口,父類沒有,父類中的屬性不能被序列化(不報錯,數據會丟失),可是在子類中屬性仍能正確序列化。
若是序列化的屬性是對象,則這個對象也必須實現serializable接口,不然會報錯
在反序列化時,若是對象的屬性有修改或刪減,則修改的部分屬性會丟失,但不會報錯
在反序列化時,若是serialVersionUID被修改,則反序列化時回失敗
6.反思下:
1) Serializable 和 Externalizable 接口有何不一樣?
2) Serializable 接口有幾個方法? 若是沒有方法,那麼爲何會有這樣的接口?
3) serialVersionUID 有何用途? 若是沒定義會有什麼問題?
4) 若是你不但願某些成員被序列化,應該怎麼作?
5) 序列化某個對象時,若是某個成員沒有實現 Serializable 會怎樣?
6) 若是某個類實現了 Serializable ,但父類沒實現,那麼當執行反序列化的時候,對象狀態是怎樣的?
7) 可否自定義序列化的過程?
8) 若是超類實現了 Serializable,那麼之類如何避免被序列化?
9) Java 在進行對象序列化和反序列化的時候,用到了哪一個方法?
10) 若是你已經將某個類的實例序列化到磁盤,這時候再往這個類添加新的屬性,那麼反序列化該對象的時候會發生什麼?
11) 什麼是 Java 序列化機制中的兼容和不兼容的變化?
12) 可否經過網絡來傳輸序列化對象?
13) 什麼類型的變量不會被序列化?
Transient修飾的屬性,不會被序列化到文件裏,原來初始化的是什麼值,最終保持的就是什麼值。