1. 程式人生 > 實用技巧 >java IO流: 序列化ObjectOutputStream/反序列化ObjectInputStream

java IO流: 序列化ObjectOutputStream/反序列化ObjectInputStream

序列化/反序列化

  • Java 提供了一種物件序列化的機制。用一個位元組序列可以表示一個物件,該位元組序列包含該物件的資料物件的型別物件中儲存的屬性等資訊。位元組序列寫出到檔案之後,相當於檔案中持久儲存了一個物件的資訊。
  • 反之,該位元組序列還可以從檔案中讀取回來,重構物件,對它進行反序列化物件的資料物件的型別物件中儲存的資料資訊,都可以用來在記憶體中建立物件。
  • 把物件以流的方式,寫入到檔案中儲存,叫寫物件,也叫物件的序列化
    • ObjectOutputStream物件的序列化流
  • 把檔案中儲存的物件,以流的方式讀取出來,叫讀物件,也叫物件的反序列化
    • ObjectInputStream
      物件的反序列化
  • 序列化和反序列化的時候,會丟擲NotSerializableException 沒有序列化異常:
    • 類通過實現java.io.Serializable 介面來啟動其序列化功能。未實現此介面的類將無法使其任何狀態序列化或反序列化
    • Serializable介面也叫標記型介面,會給類新增一個標記,序列化或反序列化時會檢測類上是否有這個標記
  • 反序列化的前提
    1. 類必須實現Serializable
    2. 必須存在類對應的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;常量,不能改變
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修飾的成員變數,不能被序列化
  • 靜態變數也不能被序列化