Java 提供了一種對象序列化的機制。用一個字節序列可以表示一個對象,該字節序列包含該對象的數據 、對象的類型 和 對象中存儲的屬性 等信息。字節序列寫出到文件之后,相當於文件中持久保存了一個對象的信息。
反之,該字節序列還可以從文件中讀取回來,重構對象,對它進行反序列化。 對象的數據 、對象的類型和對象中存儲的數據 信息,都可以用來在內存中創建對象。看圖理解序列化:
一、ObjectOutputStream
java.io.ObjectOutputStream 類,將Java對象的原始數據類型寫出到文件,實現對象的持久存儲。
構造方法
public ObjectOutputStream(OutputStream out) : 創建一個指定OutputStream的ObjectOutputStream。
構造舉例,代碼如下:
FileOutputStream fileOut = new FileOutputStream("employee.txt"); ObjectOutputStream out = new ObjectOutputStream(fileOut);
序列化操作
一個對象要想序列化,必須滿足兩個條件:
1)、該類必須實現 java.io.Serializable 接口, Serializable 是一個標記接口,不實現此接口的類將不會使任何狀態序列化或反序列化,會拋出 NotSerializableException 。
2)、該類的所有屬性必須是可序列化的。如果有一個屬性不需要可序列化的,則該屬性必須注明是瞬態的,使用@transient 關鍵字修飾。
public class Employee implements java.io.Serializable { public String name; public String address; public transient int age; // transient瞬態修飾成員,不會被序列化 public void addressCheck() { System.out.println("Address check : " + name + " ‐‐ " + address); } }
不實現serializable會報錯。
寫出對象方法
public final void writeObject (Object obj) : 將指定的對象寫出。
示例
public class SerializeDemo{ public static void main(String [] args) { Employee e = new Employee(); e.name = "zhangsan"; e.address = "beiqinglu"; e.age = 20; try { // 創建序列化流對象 ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("employee.txt")); // 寫出對象 out.writeObject(e); // 釋放資源 out.close(); fileOut.close(); System.out.println("Serialized data is saved"); // 姓名,地址被序列化,年齡沒有被序列化 } catch(IOException i) { i.printStackTrace(); } } }
二、ObjectInputStream
ObjectInputStream反序列化流,將之前使用ObjectOutputStream序列化的原始數據恢復為對象。
構造方法
public ObjectInputStream(InputStream in) : 創建一個指定InputStream的ObjectInputStream。
反序列化操作1
如果能找到一個對象的class文件,我們可以進行反序列化操作,調用 ObjectInputStream 讀取對象的方法:
public final Object readObject () : 讀取一個對象。
示例
public class DeserializeDemo { public static void main(String [] args) { Employee e = null; try { // 創建反序列化流 FileInputStream fileIn = new FileInputStream("employee.txt"); ObjectInputStream in = new ObjectInputStream(fileIn); // 讀取一個對象 e = (Employee) in.readObject(); // 釋放資源 in.close(); fileIn.close(); }catch(IOException i) { // 捕獲其他異常 i.printStackTrace(); return; }catch(ClassNotFoundException c) { // 捕獲類找不到異常 System.out.println("Employee class not found"); c.printStackTrace(); return; } // 無異常,直接打印輸出 System.out.println("Name: " + e.name); // zhangsan System.out.println("Address: " + e.address); // beiqinglu System.out.println("age: " + e.age); // 0 } }
對於JVM可以反序列化對象,它必須是能夠找到class文件的類。如果找不到該類的class文件,則拋出一個ClassNotFoundException 異常
反序列化操作2
另外,當JVM反序列化對象時,能找到class文件,但是class文件在序列化對象之后發生了修改,那么反序列化操作也會失敗,拋出一個 InvalidClassException 異常。發生這個異常的原因如下:
1)、該類的序列版本號與從流中讀取的類描述符的版本號不匹配
2)、該類包含未知數據類型
3)、該類沒有可訪問的無參數構造方法
Serializable 接口給需要序列化的類,提供了一個序列版本號。 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); } }
三、序列化集合
1. 將存有多個自定義對象的集合序列化操作,保存到 list.txt 文件中。
2. 反序列化 list.txt ,並遍歷集合,打印對象信息。
案例分析
1. 把若干學生對象 ,保存到集合中。
2. 把集合序列化。
3. 反序列化讀取時,只需要讀取一次,轉換為集合類型。
4. 遍歷集合,可以打印所有的學生信息
案例實現
public class SerTest { public static void main(String[] args) throws Exception { // 創建 學生對象 Student student = new Student("老王", "laow"); Student student2 = new Student("老張", "laoz"); Student student3 = new Student("老李", "laol"); ArrayList<Student> arrayList = new ArrayList<>(); arrayList.add(student); arrayList.add(student2); arrayList.add(student3); // 序列化操作 // serializ(arrayList); // 反序列化 ObjectInputStream ois = new ObjectInputStream(new FileInputStream("list.txt")); // 讀取對象,強轉為ArrayList類型 ArrayList<Student> list = (ArrayList<Student>)ois.readObject(); for (int i = 0; i < list.size(); i++ ){ Student s = list.get(i); System.out.println(s.getName()+"‐‐"+ s.getPwd()); } } private static void serializ(ArrayList<Student> arrayList) throws Exception { // 創建 序列化流 ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("list.txt")); // 寫出對象 oos.writeObject(arrayList); // 釋放資源 oos.close(); } }
