Java物件序列化


ObjectOutputStream類的物件用於序列化物件。ObjectInputStream類的物件用於反序列化一個物件。ObjectOutputStream繼承自OutputStreamObjectInputStream繼承自InputStream

類必須實現SerializableExternalizable介面以便序列化或反序列化。Serializable介面是一個標記介面。如果想要一個Person類的物件被序列化,需要宣告Person類如下:

public class Person   implements Serializable  {

}

Java負責處理從/向流讀取/寫入Serializable物件的細節。只需要將物件傳到流流類的write/read方法之一。實現Externalizable介面能夠更好地控制從流中讀取物件和向物件寫入物件。

它繼承Serializable介面,宣告如下:

public interface  Externalizable extends Serializable  {
    void  readExternal(ObjectInput in)  throws   IOException,  ClassNotFoundException;
    void  writeExternal(ObjectOutput out) throws   IOException;
}

當從流中讀取一個物件時,Java呼叫readExternal()方法。當向一個流寫一個物件時,它呼叫writeExternal()方法。

必須編寫邏輯來分別讀取和寫入readExternal()writeExternal()方法中的物件的欄位。

實現Externalizable介面的類如下所示:

public class Person  implements Externalizable  {
    public void  readExternal(ObjectInput in)  throws   IOException,  ClassNotFoundException {
        // Write the logic to read the Person object fields  from  the   stream
    }    
    public void  writeExternal(ObjectOutput out) throws   IOException  {
        // Write  the   logic to write Person   object fields  to the   stream
    }
}

序列化物件

以下程式碼建立ObjectOutputStream類的物件,並將物件儲存到person.ser檔案。

ObjectOutputStream oos  = new ObjectOutputStream(new FileOutputStream("person.ser"));

要將物件儲存到ByteArrayOutputStream,構造一個物件輸出流如下:

ByteArrayOutputStream baos  = new ByteArrayOutputStream();

// Creates an  object output stream to write objects to the   byte   array  output stream
ObjectOutputStream oos  = new ObjectOutputStream(baos);

使用ObjectOutputStream類的writeObject()方法通過將物件參照作為引數傳遞來序列化物件,如下所示:

oos.writeObject(p1);

最後,當完成將所有物件寫入時,使用close()方法關閉物件輸出流:

oos.close();

以下程式碼顯示Person類如何序列化,它實現可序列化介面(Serializable )。

import java.io.Serializable;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;

class Person implements Serializable {
  private String name = "Unknown";
  private String gender = "Unknown";
  private double height = Double.NaN;

  public Person(String name, String gender, double height) {
    this.name = name;
    this.gender = gender;
    this.height = height;
  }

  @Override
  public String toString() {
    return "Name: " + this.name + ", Gender:   " + this.gender + ",  Height: "
        + this.height;
  }
}

public class Main {
  public static void main(String[] args) {
    Person p1 = new Person("John", "Male", 1.7);
    Person p2 = new Person("Wally", "Male", 1.7);
    Person p3 = new Person("Katrina", "Female", 1.4);

    File fileObject = new File("person.ser");

    try (ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(
        fileObject))) {

      oos.writeObject(p1);
      oos.writeObject(p2);
      oos.writeObject(p3);

      // Display the serialized objects on the standard output
      System.out.println(p1);
      System.out.println(p2);
      System.out.println(p3);
    } catch (IOException e) {
      e.printStackTrace();
    }
  }
}

上面的程式碼生成以下結果。

Name: John, Gender:   Male,  Height: 1.7
Name: Wally, Gender:   Male,  Height: 1.7
Name: Katrina, Gender:   Female,  Height: 1.4

反序列化物件

以下程式碼顯示如何建立ObjectInputStream類的物件,並從person.ser檔案讀取物件。

ObjectInputStream ois  = new ObjectInputStream(new FileInputStream("person.ser"));

要從ByteArrayInputStream讀取物件,請按如下所示建立物件輸出流:

ObjectInputStream ois  = new ObjectInputStream(Byte-Array-Input-Stream-Reference);

使用ObjectInputStream類的readObject()方法來反序列化物件。

Object obj  = oos.readObject();

最後,關閉物件輸入流如下:

ois.close();

以下程式碼顯示如何從檔案讀取物件。

import java.io.File;
import java.io.FileInputStream;
import java.io.ObjectInputStream;

public class Main {
  public static void main(String[] args) {
    File fileObject = new File("person.ser");

    try (ObjectInputStream ois = new ObjectInputStream(new FileInputStream(
        fileObject))) {

      Person p1 = (Person) ois.readObject();
      Person p2 = (Person) ois.readObject();
      Person p3 = (Person) ois.readObject();

      System.out.println(p1);
      System.out.println(p2);
      System.out.println(p3);

    } catch (Exception e) {
      e.printStackTrace();
    }
  }
}

外部化物件序列化

要序列化和反序列化可外部化物件,請實現Externalizable介面。

import java.io.Externalizable;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectInputStream;
import java.io.ObjectOutput;
import java.io.ObjectOutputStream;

class PersonExt implements Externalizable {
    private String name = "Unknown";
    private String gender = "Unknown";
    private double height = Double.NaN;

    public PersonExt() {
    }

    public PersonExt(String name, String gender, double height) {
        this.name = name;
        this.gender = gender;
        this.height = height;
    }

    public String toString() {
        return "Name: " + this.name + ", Gender:   " + this.gender + ",  Height: " + this.height;
    }

    public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
        this.name = in.readUTF();
        this.gender = in.readUTF();
    }

    public void writeExternal(ObjectOutput out) throws IOException {
        out.writeUTF(this.name);
        out.writeUTF(this.gender);
    }
}

public class Main {
    public static void main(String[] args) {
        PersonExt p1 = new PersonExt("John", "Male", 6.7);
        PersonExt p2 = new PersonExt("Wally", "Male", 5.7);
        PersonExt p3 = new PersonExt("Katrina", "Female", 5.4);

        File fileObject = new File("personext.ser");

        try (ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(fileObject))) {
            oos.writeObject(p1);
            oos.writeObject(p2);
            oos.writeObject(p3);

            System.out.println(p1);
            System.out.println(p2);
            System.out.println(p3);
        } catch (IOException e1) {
            e1.printStackTrace();
        }

        fileObject = new File("personext.ser");

        try (ObjectInputStream ois = new ObjectInputStream(new FileInputStream(fileObject))) {

            p1 = (PersonExt) ois.readObject();
            p2 = (PersonExt) ois.readObject();
            p3 = (PersonExt) ois.readObject();

            // Let's display the objects that are read
            System.out.println(p1);
            System.out.println(p2);
            System.out.println(p3);

            // Print the input path
            System.out.println("Objects were  read   from  " + fileObject.getAbsolutePath());
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

上面的程式碼生成以下結果。

Name: John, Gender:   Male,  Height: 6.7
Name: Wally, Gender:   Male,  Height: 5.7
Name: Katrina, Gender:   Female,  Height: 5.4
Name: John, Gender:   Male,  Height: NaN
Name: Wally, Gender:   Male,  Height: NaN
Name: Katrina, Gender:   Female,  Height: NaN
Objects were  read   from  F:\website\yiibai\worksp\personext.ser