Java-序列化


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

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

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

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

ObjectOutputStream 类包含许多用于写入各种数据类型的写入方法,但有一种方法特别突出 -

public final void writeObject(Object x) throws IOException

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

public final Object readObject() throws IOException, ClassNotFoundException

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

为了演示序列化在 Java 中的工作原理,我将使用我们在本书前面讨论过的 Employee 类。假设我们有以下 Employee 类,它实现了 Serialized 接口 -

例子

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);
   }
}

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

  • 该类必须实现 java.io.Serialized 接口。

  • 类中的所有字段都必须是可序列化的。如果字段不可序列化,则必须将其标记为瞬态

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

序列化对象

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

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

注意- 将对象序列化为文件时,Java 中的标准约定是为文件提供 .ser扩展名。

例子

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

反序列化对象

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

例子

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

以下是需要注意的要点 -

  • try/catch 块尝试捕获由 readObject() 方法声明的 ClassNotFoundException。为了使 JVM 能够反序列化对象,它必须能够找到该类的字节码。如果 JVM 在对象反序列化期间找不到类,则会抛出 ClassNotFoundException。

  • 请注意,readObject() 的返回值被强制转换为 Employee 引用。

  • 对象序列化时,SSN 字段的值为 11122333,但由于该字段是瞬态的,因此该值未发送到输出流。反序列化后的Employee对象的SSN字段为0。