物件必須實作 Serializable 介面 ( 介面中沒有任何抽象方法需要實作 )
將 Student 類別 加入 Serializable 介面
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | import java.io.Serializable; public class Student implements Serializable{ private String name; private int eng; private int math; public Student(String name) throws StudentException{ if(name.length()<2){ throw new StudentException("名字不能少於兩個字"); } this.name = name; } public Student(String name, int eng, int math) { this(name);//呼叫另一個建構子 this.eng = eng; this.math = math; } @Override public String toString() { return "Student{" + "name=" + name + ", eng=" + eng + ", math=" + math + '}'; } } |
將 Student 物件 序列化,儲存檔案
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; public class ObjectOutputStreamTest { public static void main(String[] args) { Student st=new Student("Tom",100,99); try(ObjectOutputStream oos=new ObjectOutputStream(new FileOutputStream("C:/Users/Administrator/Desktop/MyJava/student.obj"))){ oos.writeObject(st); System.out.println("Student物件儲存成功"); }catch(IOException e){ System.out.println(e); } } } |
將 Student 物件 反序列化,讀取檔案
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | import java.io.FileInputStream; import java.io.IOException; import java.io.ObjectInputStream; public class ObjectInputStreamTest { public static void main(String[] args) { try (ObjectInputStream ois = new ObjectInputStream(new FileInputStream("C:/Users/Administrator/Desktop/MyJava/student.obj"))) { Student st = (Student) ois.readObject(); //Object轉型回Student System.out.println(st.toString()); } catch (IOException e) { System.out.println(e); } catch (ClassNotFoundException e) { System.out.println(e); } } } |
若修改Student類別,新增 avg 欄位,計算平均,執行 ObjectInputStreamTest,會出現版號不一致的問題
注意:每個類別都有自己的版本編號
修改後的類別,編譯器自動產生的版本編號, 與先前序列化物件的版本編號不一致,導致反序列化失敗
如何避免版號不一致的情況? 在程式自行指定版號
修改Student類別,加入版號
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | import java.io.Serializable; public class Student implements Serializable{ private static final long serialVersionUID = 1L; //自行指定版號 private String name; private int eng; private int math; public Student(String name) throws StudentException{ if(name.length()<2){ throw new StudentException("名字不能少於兩個字"); } this.name = name; } public Student(String name, int eng, int math) { this(name);//呼叫另一個建構子 this.eng = eng; this.math = math; } @Override public String toString() { return "Student{" + "name=" + name + ", eng=" + eng + ", math=" + math + '}'; } } |
刪除先前儲存的Student物件
重新執行序列化 ObjectOutputStreamTest,產生新的學生物件 (沒有平均成績)
此時修改學生類別,加入平均的程式碼
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 | import java.io.Serializable; public class Student implements Serializable{ //實作序列化界面 private static final long serialVersionUID = 1L; //自行指定版號 private String name; private int eng; private int math; private float avg; public Student(String name) throws StudentException{ if(name.length()<2){ throw new StudentException("名字不能少於兩個字"); } this.name = name; } public Student(String name, int eng, int math) { this(name);//呼叫另一個建構子 this.eng = eng; this.math = math; this.avg=(eng+math)/2.0f; } @Override public String toString() { return "Student{" + "name=" + name + ", eng=" + eng + ", math=" + math + ", avg=" + avg + '}'; // return "Student{" + "name=" + name + ", eng=" + eng + ", math=" + math + '}'; } } |
反序列化成功,但由於先前儲存的學生物件沒有平均,反序列化自動將 avg 設為 0
再度執行序列化 ObjectOutputStreamTest,現在儲存的學生有平均
執行反序列化 ObjectInputStreamTest,即可成功讀取平均成績
因平均不需要設定欄位,可以直接計算,所以使用 transient 宣告,並自定反序列化行為,在 Studnet 類別撰寫自定 readObject( ),反序列化物件時,系統會自動執行
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 | import java.io.IOException; import java.io.ObjectInputStream; import java.io.Serializable; public class Student implements Serializable{ //實作序列化界面 private static final long serialVersionUID = 1L; //自行指定版號 private String name; private int eng; private int math; transient private float avg;//宣告transient,不需要反序列化 private void readObject(ObjectInputStream stream) throws IOException, ClassNotFoundException{ stream.defaultReadObject();//執行反序列化 this.avg=(eng+math)/2.0f; } public Student(String name) throws StudentException{ if(name.length()<2){ throw new StudentException("名字不能少於兩個字"); } this.name = name; } public Student(String name, int eng, int math) { this(name);//呼叫另一個建構子 this.eng = eng; this.math = math; // this.avg=(eng+math)/2.0f; } @Override public String toString() { return "Student{" + "name=" + name + ", eng=" + eng + ", math=" + math + ", avg=" + avg + '}'; // return "Student{" + "name=" + name + ", eng=" + eng + ", math=" + math + '}'; } } |
沒有留言:
張貼留言