Java - 序列化

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

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

最令人印象深刻的是整个过程与JVM无关,这意味着一个对象可以在一个平台上序列化,并在一个完全不同的平台上进行反序列化.

类 ObjectInputStream 和 ObjectOutputStream 是包含序列化和反序列化对象的方法的高级流.

ObjectOutputStream类包含许多写方法用于编写各种数据类型,但一种方法特别突出和减去;

public final void writeObject(Object x)throws IOException

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

public final Object readObject()throws IOException,ClassNotFoundException

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

为了演示序列化在Java中的工作原理,我将使用我们早期讨论的Employee类在书中.假设我们有以下Employee类,它实现了Serializable接口 :

示例

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.Serializable接口.

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

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

序列化对象

ObjectOutputStream类用于序列化Object.以下SerializeDemo程序实例化Employee对象并将其序列化为文件.

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

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

示例

import java.io.*;
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("/tmp/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();
      }
   }
}

反序列化对象

以下DeserializeDemo程序反序列化SerializeDemo程序中创建的Employee对象.研究程序并尝试确定其输出和减号;

示例

import java.io.*;
public class DeserializeDemo {

   public static void main(String [] args) {
      Employee e = null;
      try {
         FileInputStream fileIn = new FileInputStream("/tmp/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);
   }
}

这将产生以下结果 :

输出

Deserialized Employee...
Name: Reyan Ali
Address:Phokka Kuan, Ambehta Peer
SSN: 0
Number:101

以下是需要注意的重点和减号;

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

  • 请注意,readObject()的返回值是强制转换的对于员工参考.

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