java IO流: 序列化ObjectOutputStream/反序列化ObjectInputStream
阿新 • • 發佈:2021-01-08
序列化/反序列化
- Java 提供了一種物件序列化的機制。用一個位元組序列可以表示一個物件,該位元組序列包含該
物件的資料
、物件的型別
和物件中儲存的屬性
等資訊。位元組序列寫出到檔案之後,相當於檔案中持久儲存了一個物件的資訊。 - 反之,該位元組序列還可以從檔案中讀取回來,重構物件,對它進行反序列化。
物件的資料
、物件的型別
和物件中儲存的資料
資訊,都可以用來在記憶體中建立物件。 - 把物件以流的方式,寫入到檔案中儲存,叫寫物件,也叫物件的序列化
ObjectOutputStream
:物件的序列化流
- 把檔案中儲存的物件,以流的方式讀取出來,叫讀物件,也叫物件的反序列化
ObjectInputStream
- 序列化和反序列化的時候,會丟擲
NotSerializableException
沒有序列化異常:- 類通過實現
java.io.Serializable
介面來啟動其序列化功能。未實現此介面的類將無法使其任何狀態序列化或反序列化 - Serializable介面也叫標記型介面,會給類新增一個標記,序列化或反序列化時會檢測類上是否有這個標記
- 類通過實現
- 反序列化的前提:
- 類必須實現Serializable
- 必須存在類對應的class檔案
ObjectOutputStream類:物件的序列化流
- ObjectOutputStream extends OutputStream :將Java物件的原始資料型別寫出到檔案,實現物件的持久儲存。
構造方法
public ObjectOutputStream(OutputStream out)
: 建立一個指定OutputStream的ObjectOutputStream。
特有的成員方法
void writeObject(Object obj)
: 將指定的物件寫入 ObjectOutputStream。
public class Person implements Serializable { private String name; private int age; ... } public class Demo { public static void main(String[] args) throws IOException { ObjectOutputStream oos=new ObjectOutputStream(new FileOutputStream("D:\\document\\code\\xuexi\\java\\aaa\\a.txt")); oos.writeObject(new Person("王二",90)); oos.close(); } }
ObjectInputStream類:物件的反序列化流
- ObjectInputStream extends InputStream:將之前使用ObjectOutputStream序列化的原始資料恢復為物件。
構造方法
public ObjectInputStream(InputStream in)
: 建立一個指定InputStream的ObjectInputStream。
特有的成員方法
Object readObject()
:從 ObjectInputStream 讀取物件。- readObject方法宣告丟擲了
ClassNotFoundException
(class檔案找不到異常)- 當不存在物件的class檔案時丟擲此異常
public class Demo {
public static void main(String[] args) throws IOException, ClassNotFoundException {
ObjectInputStream ois=new ObjectInputStream(new FileInputStream("D:\\document\\code\\xuexi\\java\\aaa\\a.txt"));
Object o = ois.readObject();
ois.close();
System.out.println(o);//Person{name='王二', age=90}
}
}
反序列化操作2
- 當JVM反序列化物件時,能找到class檔案,但是class檔案在序列化物件之後發生了修改,那麼反序列化操作也會失敗,丟擲一個
InvalidClassException
異常。 - 發生這個異常的原因如下:
- 該類的序列版本號與從流中讀取的類描述符的版本號不匹配 :
Serializable
介面給需要序列化的類,提供了一個序列版本號。serialVersionUID
該版本號的目的在於驗證序列化的物件和對應類是否版本匹配。 - 該類包含未知資料型別
- 該類沒有可訪問的無引數構造方法
- 該類的序列版本號與從流中讀取的類描述符的版本號不匹配 :
- 每次修改類的定義,都會給class檔案生成一個新的序列號
- 解決方案:無論是否對類的定義進行修改,都不重新生成新的序列號,可以手動新增一個序列號
- 格式在Serializable介面規定:可序列化類可以通過宣告名為 "serialVersionUID" 的欄位(該欄位必須是靜態 (static)、最終 (final) 的 long 型欄位)顯式宣告其自己的 serialVersionUID:
static final long serialVersionUID = 42L;
常量,不能改變
- 格式在Serializable介面規定:可序列化類可以通過宣告名為 "serialVersionUID" 的欄位(該欄位必須是靜態 (static)、最終 (final) 的 long 型欄位)顯式宣告其自己的 serialVersionUID:
public class Employee implements java.io.Serializable {
// 加入序列版本號
private static final long serialVersionUID = 1L;
public String name;
public String address;
// 新增新的屬性 ,重新編譯, 可以反序列化,該屬性賦為預設值.
public int eid;
public void addressCheck() {
System.out.println("Address check : " + name + " -- " + address);
}
}
transient關鍵字:瞬態關鍵字
- 被transient修飾的成員變數,不能被序列化
- 靜態變數也不能被序列化