Java 的序列化 (Serialization)(Day_09)
阿新 • • 發佈:2020-09-02
我們的火,要把世界都點燃
-
執行環境
JDK8 +IntelliJ IDEA 2018.3
-
什麼是序列化,反序列化
序列化是將物件狀態轉換為可保持或傳輸的格式的過程。
與序列化相對的是反序列化,它將流轉換為物件。這兩個過程結合起來,可以輕鬆地儲存和傳輸資料。
反序列化是指將儲存在儲存媒體中的物件狀態裝換成物件的過程
-
序列化的作用
- 以某種儲存形式使自定義物件持久化;
- 將物件從一個地方傳遞到另一個地方。
- 保證物件的完整性和可傳遞性。
- 使程式更具維護性
-
如何實現類的序列化?
實現Serializable介面
-
程式設計實現類的序列化:
1 關鍵程式碼 2 public static void main(String[] args) throws Exception{ 3 4 Student stu = new Student(); 5 6 File file = new File("bb.dat"); 7 8 ObjectOutputStream oos = new ObjectOutputStream(new 9 10 FileOutputStream(file)); 11 12 oos.writeObject(stu);13 }
-
程式設計實現類的反序列化:
1 public static void main(String[] args) throws Exception{ 2 3 File file = new File("bb.dat"); 4 5 ObjectInputStream ois = new ObjectInputStream(new 6 7 FileInputStream(file)); 8 9 Object obj = ois.readObject();10 11 System.out.println(obj.hashCode()); 12 }
-
多物件Serializable(序列化)的實現
序列化魚,還需要序列化魚的生存環境---水。
1 //環境: 水 2 import java.io.Serializable; 3 4 public class Water implements Serializable { 5 int opacity; 6 7 public Water(int opacity) { 8 this.opacity = opacity; 9 } 10 11 public Water() { 12 } 13 14 @Override 15 public String toString() { 16 return "Water{" + 17 "opacity=" + opacity + 18 '}'; 19 } 20 }
1 import java.io.Serializable; 2 3 public class Fish implements Serializable { 4 5 String color; 6 String type; 7 Water enviroment; 8 9 public Fish(String color, String type, Water enviroment) { 10 this.color = color; 11 this.type = type; 12 this.enviroment = enviroment; 13 } 14 15 public Fish(String color, String type) { 16 this.color = color; 17 this.type = type; 18 } 19 20 public Fish() { 21 } 22 23 @Override 24 public String toString() { 25 return "Fish{" + 26 "color='" + color + '\'' + 27 ", type='" + type + '\'' + 28 ", enviroment=" + enviroment + 29 '}'; 30 } 31 }
import java.io.*; // 序列化 public class TestFish { public static void main(String[] args) { Water enro = new Water(99); Fish fish = new Fish("金色", "鯉魚", enro); File file = new File("fish.bat"); try { ObjectOutputStream oos = new ObjectOutputStream( new FileOutputStream(file)); oos.writeObject(fish); oos.close(); } catch (FileNotFoundException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } } } // 反序列化 import java.io.FileInputStream; import java.io.IOException; import java.io.ObjectInputStream; public class TestFish2 { public static void main(String[] args) { try { ObjectInputStream objectInputStream=new ObjectInputStream(new FileInputStream("fish.bat")); try { Fish fish=(Fish) objectInputStream.readObject(); System.out.println(fish); objectInputStream.close(); } catch (ClassNotFoundException e) { e.printStackTrace(); } } catch (IOException e) { e.printStackTrace(); } } }
¤ransient關鍵字:將不需要序列化的屬性前新增關鍵字transient,序列化物件的時候,這個屬性就不會被序列化。
- 淺克隆 —— 只克隆本身
被複制物件的所有變數都含有與原來物件相同的值,而所有的對其他物件的引用仍然只指向原來的物件。
程式碼演示:
1 package com.wenhaitao.yxdemo.demo4; 2 public class Professor { 3 String name; 4 int age; 5 6 public Professor(String name, int age) { 7 super(); 8 this.name = name; 9 this.age = age; 10 } 11 12 public Professor() { 13 super(); 14 } 15 16 @Override 17 public String toString() { 18 return "Professor [age=" + age + ", name=" + name + "]"; 19 } 20 21 }
1 // 淺克隆 2 3 public class Student implements Cloneable { 4 String name; 5 int age; 6 7 Professor p; 8 9 public Professor getP() { 10 return p; 11 } 12 13 public void setP(Professor p) { 14 this.p = p; 15 } 16 17 @Override 18 public Object clone() throws CloneNotSupportedException { 19 return super.clone(); 20 } 21 22 public Student() { 23 super(); 24 } 25 26 public Student(String name, int age) { 27 super(); 28 this.name = name; 29 this.age = age; 30 } 31 32 public Student(String name, int age, Professor p) { 33 super(); 34 this.name = name; 35 this.age = age; 36 this.p = p; 37 } 38 39 @Override 40 public String toString() { 41 return "Student [age=" + age + ", name=" + name + ", p=" + p + "]"; 42 } 43 44 public static void main(String[] args) throws CloneNotSupportedException { 45 Professor p = new Professor("feifeiye",50); 46 Student s1 = new Student("zhangsan", 19, p); 47 Student s2 = (Student) s1.clone(); 48 System.out.println(s1); 49 System.out.println(s2); 50 System.out.println(s1==s2); 51 52 s2.p.name = "wangwu"; 53 s2.p.age = 90; 54 System.out.println(s2); 55 System.out.println(s1); 56 } 57 }
- 深克隆 ——克隆本身和所有的成員
概述:
被複制物件的所有變數都含有與原來的物件相同的值,除去那些引用其他物件的變數,
那些引用其他物件的變數將指向被複制過的新物件,而不再指向原有的那些被引用的物件,
換言之,深複製把要複製的物件所引用的物件都複製了一遍。
程式碼演示:
1 2 public class Professor implements Cloneable{ 3 String name; 4 int age; 5 6 public Professor(String name, int age) { 7 super(); 8 this.name = name; 9 this.age = age; 10 } 11 12 public Professor() { 13 super(); 14 } 15 16 public Object clone() throws CloneNotSupportedException { 17 return super.clone(); 18 } 19 20 21 @Override 22 public String toString() { 23 return "Professor [age=" + age + ", name=" + name + "]"; 24 } 25 26 }
1 //深克隆 2 public class Student implements Cloneable { 3 String name; 4 int age; 5 6 Professor p; 7 8 public Professor getP() { 9 return p; 10 } 11 12 public void setP(Professor p) { 13 this.p = p; 14 } 15 16 @Override 17 public Object clone() throws CloneNotSupportedException { 18 Object obj = super.clone(); 19 Student s = (Student) obj; 20 s.p = (Professor) this.p.clone(); 21 return obj; 22 } 23 24 public Student() { 25 super(); 26 } 27 28 public Student(String name, int age) { 29 super(); 30 this.name = name; 31 this.age = age; 32 } 33 34 public Student(String name, int age, Professor p) { 35 super(); 36 this.name = name; 37 this.age = age; 38 this.p = p; 39 } 40 41 @Override 42 public String toString() { 43 return "Student [age=" + age + ", name=" + name + ", p=" + p + "]"; 44 } 45 46 public static void main(String[] args) throws CloneNotSupportedException { 47 Professor p = new Professor("肥肥也",19); 48 Student s1 = new Student("都一樣", 19, p); 49 Student s2 = (Student) s1.clone(); 50 System.out.println(s1);// 51 System.out.println(s2); 52 System.out.println(s1==s2); 53 54 s2.p.name = "zhaoliu"; 55 s2.p.age = 60; 56 System.out.println(s2);// 57 System.out.println(s1); 58 } 59 }
總結:
- 如果自定義型別包含引用型別的資料成員,必須考慮Clone方法是實現淺拷貝(shallow copy)還是深拷貝(deep copy)。
- 淺拷貝是指副本物件中的引用型別的資料成員與源物件的資料成員指向相同的物件。而如果是深拷貝,則必須建立整個物件的結構,副本物件中的引用 型別的資料成員與源物件的資料成員指向不同的物件。
- 當一個父類實現序列化,子類自動實現序列化,不需要顯式實現Serializable介面;
- 當一個物件的例項變數引用其他物件,序列化該物件時也把引用物件進行序列化;
PS: