1. 程式人生 > >Java學習筆記(十三)--序列化、反序列化與無參建構函式

Java學習筆記(十三)--序列化、反序列化與無參建構函式

概念

  1. 序列化:將物件儲存到磁碟中,或允許在網路中直接傳輸物件,物件序列化機制允許把記憶體中的Java物件轉換成平臺無關的二進位制,從而可以持久的儲存在磁碟上,也可以在網路中傳輸。
  2. 反序列化:程式一旦獲得了序列化的物件,則這種二進位制流都可以恢復成原來的

如何實現序列化

    1.Serializable

要序列化的物件,實現該介面,無需重寫任何方法

    2.Externalizable

要序列化的物件實現該介面,並且需要實現writeExternal和readExternal方法

簡單物件的序列化

 1.單一的物件序列化

  • 建立一個Person類
public class Person implements Serializable{
    private String id;

    public Person(String id) {
        System.out.println("youcacn");
        this.id = id;
    }

    @Override
    public String toString() {
        return "Person{" +
                "id='" + id + '\'' +
                '}';
    }

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }
}

   注意:1.Person類實現了Serializable介面

           2.該實體類沒有提供無參建構函式

  •  寫一個測試類,測試一下序列化與反序列化      
try {
            //序列化
            ObjectOutputStream objectOutputStream = new ObjectOutputStream(new FileOutputStream("2.txt"));
            Person person = new Person("111");
            objectOutputStream.writeObject(person);
            //反序列化
            ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream("2.txt"));
            Person person1 = (Person) objectInputStream.readObject();
            System.out.println(person1.toString());
        } catch (Exception e) {
            e.printStackTrace();
        }
  •    執行結果


  •   Person類去掉實現序列化介面(即,將public class Person implements Serializable修改為public class Person),重新執行


   結論:簡單型別(無繼承關係)物件序列化時必須實現序列化介面,有無無參建構函式都key

2.存在繼承關係,但並無引用關係的物件序列化

  • 建立Student類,繼承Person類
public class Student extends Person implements Serializable{
    private int no;

    @Override
    public String toString() {
        return "Student{" +
                "no=" + no +
                '}';
    }

    public Student(String id ,int no) {
        super(id);
        this.no = no;
    }

    public int getNo() {
        return no;
    }

    public void setNo(int no) {
        this.no = no;
    }

}
  • Person類物件既沒實現序列化介面,又沒有提供無參建構函式
public class Person{
    private String id;

//    public Person() {
//    }

    public Person(String id) {
        System.out.println("youcacn");
        this.id = id;
    }

    @Override
    public String toString() {
        return "Person{" +
                "id='" + id + '\'' +
                '}';
    }

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }
}
  • 執行序列化與反序列化

  • 另Person物件實現序列化介面,再次執行,結果成功
public class Person implements Serializable{
    private String id;

//    public Person() {
//    }

    public Person(String id) {
        System.out.println("youcacn");
        this.id = id;
    }

    @Override
    public String toString() {
        return "Person{" +
                "id='" + id + '\'' +
                '}';
    }

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }
}
  • 不實現序列化介面,提供無參建構函式,執行結果成功
public class Person {
    private String id;

    public Person() {
    }

    public Person(String id) {
        System.out.println("youcacn");
        this.id = id;
    }

    @Override
    public String toString() {
        return "Person{" +
                "id='" + id + '\'' +
                '}';
    }

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }
}
  結論:存在繼承關係時,若想序列化子類物件,一併序列化父類物件,則負責型別必須實現序列化介面或者提供無參建構函式

物件引用的序列化

  •     Student類繼承Person類,並有物件引用關係
public class Student extends Person implements Serializable {
    private int no;
    private Person person;

    public Person getPerson() {
        return person;
    }

    public void setPerson(Person person) {
        this.person = person;
    }
        
    @Override
    public String toString() {
        return "Student{" +
                "no=" + no +
                '}';
    }

    public Student(String id, int no) {
        super(id);
        this.no = no;
    }

    public int getNo() {
        return no;
    }

    public void setNo(int no) {
        this.no = no;
    }

}
  • 一個demo序列化Student例項與反序列化Student例項
try {
            //序列化
            ObjectOutputStream objectOutputStream = new ObjectOutputStream(new FileOutputStream("2.txt"));
            Person person = new Person("111");
            Student stuB = new Student("B", 163);
            stuB.setPerson(person);
            objectOutputStream.writeObject(stuB);
            //反序列化
            ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream("2.txt"));
            Student student  = (Student) objectInputStream.readObject();
            System.out.println(student.getPerson());
        } catch (Exception e) {
            e.printStackTrace();
        }
  • Person類不實現序列化介面,也不提供無參建構函式,執行結果如下:

  • Person類不實現序列化介面,提供無參建構函式,執行結果如下:


  • Person類實現序列化介面,但不提供無參建構函式,執行結果如下:


結論

  1. 單一物件,無繼承關係:若想實現序列化與反序列化,則必須實現序列化介面,否則報異常:NotSerializableException
  2. 物件間有繼承關係,但無引用關係,若想實現序列化與反序列化,則父類必須實現序列化介面或提供無參建構函式,否則報invalidClassException
  3. 物件間有繼承關係,並且有引用關係,若想實現序列化與反序列化,則父類必須實現序列化介面