java的序列化和反序列化

java的序列化和反序列化

目录

  • java的序列化和反序列化
    • java序列化
    • java反序列化
      • 为什么要将java对象序列化
      • 序列化作用
      • 序列化和反序列化步骤
        • 创建一个实现了Serializable接口的对象
        • 序列化一个对象
        • 反序列化对象

java序列化

Java中的序列化是指将对象转换为字节流的过程。

java反序列化

Java反序列化就是把字节序列恢复为Java对象的过程。
java的序列化和反序列化_第1张图片

为什么要将java对象序列化

Java对象是运行在JVM的堆内存中的,如果JVM停止后,那么java对象的生命也就终止了。如果我们想在JVM停止后把这些对象保存到磁盘或想通过网络传输,这时候就需要序列化了

序列化作用

序列化机制可以将对象保存到硬盘中起到持久化作用,并且使Java对象在网络中传输成为可能。

序列化和反序列化步骤

创建一个实现了Serializable接口的对象

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

该类的所有属性必须是可序列化的。如果有一个属性不是可序列化的,则该属性必须使用transient变量
java中的序列化时transient变量(这个关键字的作用就是告知JAVA不可以被序列化)和静态变量不会被序列化

序列化一个对象

使用ObjectOutputStream类的writeObject方法

import java.io.*;

public class SerializeDemo {
   public static void main(String [] args) {
      Employee e = new Employee(); // 创建一个Employee对象
      e.name = "Reyan Ali"; // 设置Employee对象的姓名属性
      e.address = "Phokka Kuan, Ambehta Peer"; // 设置Employee对象的地址属性
      e.SSN = 11122333; // 设置Employee对象的社会保险号码属性
      e.number = 101; // 设置Employee对象的编号属性
      
      try {
         FileOutputStream fileOut = new FileOutputStream("/tmp/employee.ser"); // 准备输出流,将序列化后的数据保存在文件 "/tmp/employee.ser" 中
         ObjectOutputStream out = new ObjectOutputStream(fileOut); // 创建一个对象输出流,用于将对象序列化后写入文件
         out.writeObject(e); // 将Employee对象写入输出流,进行序列化
         out.close(); // 关闭对象输出流
         fileOut.close(); // 关闭文件输出流
         System.out.printf("Serialized data is saved in /tmp/employee.ser"); // 打印提示信息,表示对象已经成功序列化并保存到文件中
      } catch(IOException i) {
         i.printStackTrace(); // 捕获IO异常,打印异常堆栈信息
      }
   }
}
反序列化对象

使用ObjectInputStream类的readObject方法

import java.io.*;

public class DeserializeDemo {
   public static void main(String [] args) {
      Employee e = null; // 声明一个Employee对象,初始值为null

      try {
         FileInputStream fileIn = new FileInputStream("/tmp/employee.ser"); // 创建一个文件输入流,用于读取序列化的对象数据文件
         ObjectInputStream in = new ObjectInputStream(fileIn); // 创建一个对象输入流,用于从文件中读取对象
         e = (Employee) in.readObject(); // 从输入流中读取对象,并将其转换为Employee类型
         in.close(); // 关闭对象输入流
         fileIn.close(); // 关闭文件输入流
      } catch(IOException i) {
         i.printStackTrace(); // 捕获IO异常,打印异常堆栈信息
         return; // 返回
      } catch(ClassNotFoundException c) {
         System.out.println("Employee class not found"); // 捕获ClassNotFoundException异常,打印异常信息
         c.printStackTrace(); // 打印异常堆栈信息
         return; // 返回
      }

      System.out.println("Deserialized Employee...");
      System.out.println("Name: " + e.name); // 打印反序列化后的Employee对象的姓名
      System.out.println("Address: " + e.address); // 打印反序列化后的Employee对象的地址
      System.out.println("SSN: " + e.SSN); // 打印反序列化后的Employee对象的社会保险号码
      System.out.println("Number: " + e.number); // 打印反序列化后的Employee对象的编号
   }
}

这里要注意以下要点:
readObject() 方法中的 try/catch代码块尝试捕获 ClassNotFoundException 异常。对于 JVM 可以反序列化对象,它必须是能够找到字节码的类。如果JVM在反序列化对象的过程中找不到该类,则抛出一个 ClassNotFoundException 异常。
注意,readObject() 方法的返回值被转化成 Employee 引用。
当对象被序列化时,属性 SSN 的值为 111222333,但是因为该属性是短暂的,该值没有被发送到输出流。所以反序列化后 Employee 对象的 SSN 属性为 0

如果某个序列化类的成员变量是对象类型,则该对象类型的类必须实现序列化

如果先序列化对象A后序列化B,那么在反序列化的时候一定记着JAVA规定先读到的对象是先被序列化的对象,不要先接收对象B,否则会报错。尤其在使用上面的Externalizable的时候一定要注意读取的先后顺序

实现序列化接口的对象并不强制声明唯一的serialVersionUID,是否声明serialVersionUID对于对象序列化的向上向下的兼容性有很大的影响

你可能感兴趣的:(开发语言,java)