Java 教程

Java 控制语句

面向对象编程

Java 内置类

Java 文件处理

Java 错误与异常

Java 多线程

Java 同步

Java 网络编程

Java 集合

Java 接口

Java 数据结构

Java 集合算法

高级 Java

Java 其他

Java APIs 与框架

Java 类引用

Java 有用资源

Java - 序列化



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

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

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

序列化和反序列化对象的方法

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

ObjectOutputStream 类包含许多用于写入各种数据类型的写入方法,但其中一种方法尤其突出:

语法

public final void writeObject(Object x) throws IOException

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

语法

public final Object readObject() throws IOException, ClassNotFoundException

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

Java 中的序列化是如何工作的?

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

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

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

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

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

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

序列化对象

ObjectOutputStream 类用于序列化 Object。以下 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

Java序列化要点

以下是需要注意的一些要点:

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

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

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

广告