序列化流
java提供了一種對象序列化的機制,用一個字節序列可以表示一個對象,該字節序列包含該對象的數據,對象的類型和對象中存儲的屬性等信息,字節序列寫入到文件中后,就相當於在文件中保存了文件對象信息.
反之,該字節序列還可以從文件中讀取出來,重構對象.對他進行反序列化.對象的數據,對象的類型和對象中存儲的數據信息,都可以用來在內存中創建對象,
ObjectOutputStream類
java.io.ObjectOutputStream類,將java對象的原始數據類型寫入到文件中,實現對象的持久化存儲.
構造方法
-
public ObjectPutputStream(OutputStream out):創建一個指定的OutputStream的的ObjectOutputStream類對象
獨有的方法
-
void writeObject(Object obj):將指定的對象寫入到對象序列化中
備注:
當某個類對象需要進行序列化時,沒有實現序列化接口時會拋出該 java.io.NotSerializableException 序列化異常 解決:讓該類實現Serializable接口,啟用序列化功能,為實現此接口的類將無法使其 任何狀態序列化或者進行反序列化. java.io.Serializable接口, 此接口內部什么也沒有,這類接口也可稱為標記性接口. 要進行序列化和反序列化的時候,給該類添加一個標記,實現序列化接口,此時該類就有標記了. 當程序要進行序列化和反序列化的時候,首先會檢測該類是否有序列化標記. 有:就可以進行序列化和反序列化 沒有:就會拋出java.io.NotSerializableException 就好比大家上超市買產品,需要看產品上的生產日期
序列化操作
1.一個對象想要能夠序列化和反序列化,必須滿足兩個條件:
-
該類必須實現java.io.Serializable接口,Serializable接口是一個標記性接口,如果該類沒有實現Serializable接口,將會拋出NotSerializableException.
-
該類的所有屬性必須是可以實現序列化或者反序列化,如果有一個屬性不想讓他參與序列化,則該屬性必須標明是 瞬態的,瞬時的,這個關鍵字是transient,被他修飾的成員變量是沒有值的.為默認值.
public class Student implements Serializable{
private String name;
private transient int age;//讓age屬性不參與序列化
ObjectinputStream類
ObjectInputStream類是反序列化流,將之前使用ObjectOutputStream序列化流的原始數據恢復為對象.
構造方法
-
public ObjectunputStream(inmputStream in):創建一個指定的inputStream的對象反序列化流對象.
特有的方法:
-
public final Object readObject():從反序列化流中讀取對象
做好了一個類繼承了可序列化標記好,虛擬機可以給它一個序列號.序列化存儲對象文件之后,更改了類源代碼,那么這個類會更新另一個序列號,那么對象文件在反序列化的時候就會報錯.
所以我們面對類的序列號進行鎖定,自定義一個
//可以手動自定義一個序列化版本號
private static final long serialVersionUID=1L;
鎖定了序列號之后,對類進行了修改,那么反編譯會通過,但是他會屬性對照,類中此時還在的屬性才會被抓取,而類中新增的成員變量此時不存在.
對於JVM來說,能夠進行反序列的對象,前提條件是必須能夠找到class文件的類,如果找不到該類的class文件,則會跑出一個ClassNotFoundException異常.
另外,當JVM序列化對象時,能找找到class文件,但是class文件再序列化對象時,發生了修改,那么反序列化操作會拋出invalidClassException異常.原因如下:
-
該類的序列化版本號與從流中讀取出來描述該類的版本號不一致.
-
該類包含了位置數據類型.
-
該類沒有可訪問的無參構造方法.
Serializable接口給需要序列化的類,提供了一個序列化版本號,seriaIVersionUID改版本號的目的就在於驗證序列化的對象和對應的類是否是版本一致.
//可以手動自定義一個序列化版本號
private static final long serialVersionUID=11231L;