什麼是java序列化,如何實現? 序列化就是一種用來處理物件流的機制,所謂物件流也就是將物件的內容進行流化。可以對流化後的物件進行讀寫操作,也可將流化後的物件傳輸於網路之間。 序列化是為了解決在對 物件進行讀寫操作時所引發的問題。 序列化的實現:將需要被序列化的類實現Serializable介面,該介面沒有需要被實現的方法,implement Serializable只是為了標註該物件是可被序列化的,然後使用 一個輸出流(如:fileOutputStream)來構造一個ObjectOutputStream(物件流)物件,接著,使用ObjectOutputStream物件的writeObject方法就可以 將引數為obj的物件寫出(即儲存其狀態),要恢復的話則利用輸入流。 SerialVersionUID--下面簡稱SUID 其實序列化的作用是能轉化成Byte流,然後又能反序列化成原始的類。能在網路進行傳輸,也可以儲存在磁碟中,有了SUID之後,那麼如果序列化的類已經儲存了在本地中,中途你更改了類後,SUID變了,那麼反序列化的時候就不會變成原始的類了,還會拋異常,主要就是用於版本控制。 SUID:IDE一般會幫你自動生成,其實這個值你可以自己設定,只要保證id值唯一就好。你可以理解成唯一標識。 serialVersionUID是用於記錄class檔案的版本資訊的,serialVersionUID這個數字是透過一個類的類名、成員、包名、工程名算出來的。 使用ObjectInputStream 反序列化的時候,ObjectInputStream會先讀取檔案中的serialVersionUID,然後與本地的class檔案的serialVersionUID進行對比,如果這兩個id不一致,那麼反序列化就失敗了。 物件的輸入輸出流,主要的作用是用於寫物件與讀取物件的資訊。對資訊一旦寫到檔案上那麼物件的資訊就可以持久化了
package com.io.test; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.*; import java.util.*;public class Test implements Serializable {//Serializable介面沒有任何方法,只是一個標識介面 public static void main(String[] args) throws Exception { new Test().test(); } private void test() throws FileNotFoundException, IOException, ClassNotFoundException { Map<Integer, Film> map = new HashMap<Integer, Film>(); map.put(1, new Film("變形金剛", 20)); map.put(2, new Film("鋼鐵俠", 30)); map.put(3, new Film("復仇者聯盟", 40)); /*,序列化其實就是將film的相關資訊轉化為二進位制儲存在了map.txt這個檔案中,那麼用文字編輯器開啟檢視的話當然是會出現亂碼的。只有透過反序列化才能將儲存的二進位制讀取出來,然後正常顯示在控制檯上。*/ ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("map.txt")); oos.writeObject(map); oos.close(); /*反序列化*/ ObjectInputStream ois = new ObjectInputStream(new FileInputStream("map.txt")); Map<Integer, Film> m = new HashMap<Integer, Film>(); m = (Map<Integer, Film>) ois.readObject(); ois.close(); System.out.println(m.toString()); } class Film implements Serializable { //先執行序列化方法 唯一標識是1L 然後改成2L後 反序列化輸出會報錯 private static final long serialVersionUID = 1L; private String name; private int duration; public Film(String name, int duration) { this.name = name; this.duration = duration; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getDuration() { return duration; } public void setDuration(int duration) { this.duration = duration; } public Film() { } @Override public String toString() { return "Film{" + "name='" + name + '\'' + ", duration=" + duration + '}'; } } }
物件輸入輸出流要注意的細節
- 如果物件需要被寫到檔案上,那麼物件所屬的類必須實現Serializable介面,Serializable介面沒有任何方法,只是一個標識介面。
- 物件的反序列化建立物件的時候並不會呼叫到構造方法的。
- serialVersionUID是用於記錄class檔案的版本資訊的,serialVersionUID這個數字是透過一個類的類名、成員、包名、工程名算出來的。
- 使用ObjectInputStream 反序列化的時候,ObjectInputStream會先讀取檔案中的serialVersionUID,然後與本地的class檔案的serialVersionUID進行對比,如果這兩個id不一致,那麼反序列化就失敗了。
- 如果序列化與反序列化的時候可能會修改類的成員,那麼最好一開始就給這個類指定一個serialVersionUID,如果一個類制定了serialVersionUID,然後再序列化和反序列化的時候,jvm都不會再自己算這個serialVersionUID
- 如果一個物件某個資料不想被序列化到硬碟上,可以使用關鍵字transient修飾
- 如果一個類維護了另外一個類的引用,那麼另外一個類也需要實現Serializable介面