網(wǎng)頁設(shè)計網(wǎng)站建設(shè)招聘軟文寫作平臺發(fā)稿
序列化和反序列化
- 序列化和反序列化
- 作用
- 為什么需要
- 用途
- Serializable
- 使用
- serialVersionUID
- 不設(shè)置的后果
- 什么時候修改
- Externalizable
- 序列化的順序
- json序列化
序列化和反序列化
序列化
:把對象轉(zhuǎn)換為字節(jié)序列的過程稱為對象的序列化。
反序列化
:把字節(jié)序列恢復(fù)為對象的過程稱為對象的反序列化。
其實就是將代碼中運行的對象從內(nèi)存中保存為字節(jié)序列可以存儲和傳輸。
作用
- 把對象的字節(jié)序列永久地保存到硬盤上(通常存放在一個文件中);
- 在網(wǎng)絡(luò)上傳送對象的字節(jié)序列。
為什么需要
Java對象是運行在JVM的堆內(nèi)存中的,如果JVM停止后,它的生命也就戛然而止。
如果想在JVM停止后,把這些對象如何保存起來呢。我們只能保存到硬盤上或者傳輸?shù)狡渌胤搅?#xff0c;但是很多硬件或者說傳輸只支持二進制而不認識java的對象,所以需要將這些對象轉(zhuǎn)換成字節(jié)序列了。
我感覺和高級語言編譯成二進制差不多。java對象是我們好理解的,二進制是機器理解的。
用途
- 可以做對象的備份會恢復(fù)
- 兼容性規(guī)定
- 數(shù)據(jù)存儲,保存到數(shù)據(jù)庫、文件等
- 傳輸
怎么樣序列化需要我們來規(guī)定,所以學(xué)習(xí)這些規(guī)定的方法
如果不規(guī)定則會報錯
MyArrayList 是自己實現(xiàn)的一個動態(tài)數(shù)組的類,還未實現(xiàn)Serializable接口
public void testSerializable() {MyArrayList list = new MyArrayList();for (int i = 0; i < 100; i++) {list.add(i);}try(ObjectOutputStream o = new ObjectOutputStream(new FileOutputStream("a.txt"));ObjectInputStream in = new ObjectInputStream(new FileInputStream("a.txt"));) {o.writeObject(list);MyArrayList l = (MyArrayList) in.readObject();System.out.println(l);} catch (IOException | ClassNotFoundException e) {throw new RuntimeException(e);}
}
會出現(xiàn)這樣的錯誤
Serializable
Serializable接口是一個標(biāo)記接口,沒有方法或字段。一旦實現(xiàn)了此接口,就標(biāo)志該類的對象就是可序列化的。
這種是隱式序列化(不需要手動),這種是最簡單的序列化方式,會自動序列化所有非static和 transient關(guān)鍵字修飾的成員變量
使用
實現(xiàn)之后在運行上面代碼
a.txt,看不懂的
serialVersionUID
意思就是序列化版本號ID,其實每一個實現(xiàn)Serializable接口的類,都有一個表示序列化版本標(biāo)識符的靜態(tài)變量,或者默認等于1L,或者等于對象的哈希碼。
JAVA序列化的機制是通過判斷類的serialVersionUID來驗證版本是否一致的。在進行反序列化時,會把serialVersionUID和本地相應(yīng)實體類的serialVersionUID進行比較,如果相同,反序列化成功,如果不相同,就拋出InvalidClassException異常。
修改一下在讀取,記得注釋掉序列化的代碼
不設(shè)置的后果
在類中新增一個不使用的字段
然后序列化后刪除這個字段
我們會發(fā)現(xiàn)其報錯
Caused by: java.io.InvalidClassException:
com.yu.MyArrayList; local class incompatible:stream classdesc serialVersionUID = 8278873907900787181, local class serialVersionUID = -9196603521067733754
我們不是沒有設(shè)置這個字段嗎,怎么報錯會顯示這個呢。這個是怎么來的
在沒有定義 serialVersionUID的時候,就會生成默認的序列化唯一標(biāo)示。
他的生成規(guī)則是根據(jù)類名,方法和屬性等參數(shù)生成的 hash 值
所以在刪除后其hash值會改變。
但是這個字段對于我們來說毫無影響,所以我們可以自行設(shè)置serialVersionUID 的值
在進行上面操作且不修改serialVersionUID 的值,會發(fā)現(xiàn)代碼通過了。
什么時候修改
在阿里巴巴開發(fā)手冊中有
不是說一定不能修改,在不兼容的時候在修改。
就像上面的這個字段對代碼毫無影響,那么我們就不需要修改了。
這個應(yīng)該強制一下實現(xiàn)了這個接口的就必須賦初值,不然隨便修改一下屬性就不能反序列化了。
這就是差不多是一個兼容性問題,就像各個版本的JDK代碼都拿出來看一下,那些向下兼容的類的serialVersionUID是沒有變化過的。
Externalizable
Externalizable繼承了Serializable接口,還定義了兩個抽象方法:writeExternal()和readExternal(),如果開發(fā)人員使用Externalizable來實現(xiàn)序列化和反序列化,需要重寫writeExternal()和readExternal()方法
這2個方法給定了流,直接調(diào)用流的方法自定義讀和寫就行
如我什么都不序列化,獲取里面的大小就是0
只序列化大小
如果我序列化大小和容量,打印數(shù)據(jù)就會報錯。
因為我們的類中的數(shù)組沒有這么大初始為空,所以會報錯。
序列化的順序
那么我們?nèi)绻貜?fù)序列化size會發(fā)生什么
獲取其中的size和capacity
我們來混亂的定義
打印結(jié)果
可以看到順序和我們序列化的順序一樣和屬性無關(guān)
最后我們用不同屬性進行
發(fā)現(xiàn)了幾點規(guī)律
接收和發(fā)送順序完全一樣,不會是int讀int,object讀object。
順序錯了會報錯
不同類型混合接收
至于為什么是這樣,應(yīng)該涉及太底層的,我還不知道,到時候看流的底層的時候在看看。
json序列化
json使用就比較簡單
但是會報錯。
這里看到只序列化了size。
因為fastjson會掃描其中的getter方法,我們只設(shè)置了getSize方法。
所以其他的訪問不到。
json的具體內(nèi)容以后在說,這里只介紹其普通使用。