Java 简明教程

Java - Serialization

Java 提供了一种机制,称为对象序列化,其中一个对象可以表示为包含该对象的数据以及有关对象类型和存储在 object中的数据类型的信息的字节序列。

将序列化对象写到文件后,可以从文件读取它并对其反序列化,即类型信息和表示对象及其数据的字节可用于在内存中重新创建该对象。

最令人印象深刻的是,整个过程都是 JVM独立,这意味着一个对象可以在一个平台上序列化,并在一个完全不同的平台上反序列化。

Methods for Serializing and Deserializing an Object

ObjectInputStreamObjectOutputStream是包含用于序列化和反序列化对象的方法的高级流。

ObjectOutputStream 类包含很多用于写入各种 data types的写入方法,但有一个方法特别突出−

Syntax

public final void writeObject(Object x) throws IOException

以上方法对 Object 序列化并将它发送到输出流中。类似地,ObjectInputStream 类包含以下用于反序列化对象的 -

Syntax

public final Object readObject() throws IOException, ClassNotFoundException

此方法从流中检索下一个 Object 并对其进行反序列化。返回值为 Object,因此你需要将其强制转换为其适当的数据类型。

How Serialization Works in Java?

为了演示序列化如何在 Java 中工作,我将使用我们在本书开头讨论过的 Employee 类。假设我们有以下一个实现了 Serializable 接口的 Employee 类:

Example to Demonstrate Working of Serialization in Java

public class Employee implements java.io.Serializable {
   public String name;
   public String address;
   public transient int SSN;
   public int number;

   public void mailCheck() {
      System.out.println("Mailing a check to " + name + " " + address);
   }
}

请注意,若要成功序列化一个类,必须满足两个条件:

  1. 类必须实现 java.io.Serializable 接口。

  2. 类中的所有字段都必须可序列化。如果一个字段不可序列化,则必须标记为 transient

如果你好奇一个 Java 标准类是否可序列化,请查看该类的文档。测试很简单:如果该类实现了 java.io.Serializable,那么它是可序列化的;否则,它不可序列化。

Serializing an Object

ObjectOutputStream 类用于序列化一个对象。以下 SerializeDemo 程序实例化一个 Employee 对象,并将其序列化到一个文件中。

当程序执行完毕时,会创建一个名为 employee.ser 的文件。该程序不会生成任何输出,但研究该代码,并尝试确定该程序正在做什么。

Note - 当将一个对象序列化到一个文件中时,Java 中的标准惯例是给该文件一个 .ser 扩展名。

Example for Serializing an Object

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

public class SerializeDemo {

   public static void main(String [] args) {
      Employee e = new Employee();
      e.name = "Reyan Ali";
      e.address = "Phokka Kuan, Ambehta Peer";
      e.SSN = 11122333;
      e.number = 101;

      try {
         FileOutputStream fileOut = new FileOutputStream("employee.ser");
         ObjectOutputStream out = new ObjectOutputStream(fileOut);
         out.writeObject(e);
         out.close();
         fileOut.close();
         System.out.printf("Serialized data is saved in /tmp/employee.ser");
      } catch (IOException i) {
         i.printStackTrace();
      }
   }
}
class Employee implements java.io.Serializable {
   private static final long serialVersionUID = 1L;
   public String name;
   public String address;
   public transient int SSN;
   public int number;

   public void mailCheck() {
      System.out.println("Mailing a check to " + name + " " + address);
   }
}
Serialized data is saved in employee.ser

Deserializing an Object

以下 DeserializeDemo 程序反序列化在前面程序中创建的 Employee 对象。研究该程序并尝试确定其输出:

Example for Deserializing an Object

import java.io.FileInputStream;
import java.io.IOException;
import java.io.ObjectInputStream;

public class DeserializeDemo {

   public static void main(String [] args) {
      Employee e = null;
      try {
         FileInputStream fileIn = new FileInputStream("employee.ser");
         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("Deserialized Employee...");
      System.out.println("Name: " + e.name);
      System.out.println("Address: " + e.address);
      System.out.println("SSN: " + e.SSN);
      System.out.println("Number: " + e.number);
   }
}
class Employee implements java.io.Serializable {

   private static final long serialVersionUID = 1L;
   public String name;
   public String address;
   public transient int SSN;
   public int number;

   public void mailCheck() {
      System.out.println("Mailing a check to " + name + " " + address);
   }
}
Deserialized Employee...
Name: Reyan Ali
Address:Phokka Kuan, Ambehta Peer
SSN: 0
Number:101

Importing Points About Serialization in Java

以下是要注意的几个重点:

  1. try/catch block尝试捕获 ClassNotFoundException,该异常由 readObject() 方法声明。对于 JVM 能够反序列化一个对象,它必须能够找到该类的字节码。如果在对象的序列化期间 JVM 无法找到一个类,则它将抛出 ClassNotFoundException。

  2. 请注意, readObject()的返回值会被强制转换为一个 Employee 引用。

  3. 当该对象被序列化时,SSN 字段的值为 11122333,但由于该字段是短暂的,因此此值不会被发送到输出流中。反序列化的 Employee 对象的 SSN 字段为 0。