Java 中的基本序列化

什么是序列化

序列化是将对象的状态(包括其引用)转换为字节序列的过程,以及在将来某个时间将这些字节重建为活动对象的过程。如果要保留对象,则使用序列化。Java RMI 也使用它来在 JVM 之间传递对象,作为从客户端到服务器的方法调用中的参数,或者作为方法调用的返回值,或者作为远程方法抛出的异常。通常,当我们希望对象在 JVM 的生命周期之外存在时,使用序列化。

java.io.Serializable 是一个标记界面(没有主体)。它仅用于将 Java 类标记为可序列化。

与每个序列化类版本号,称为 serialVersionUID,该过程中使用的序列化运行时相关联 -serialization 以验证序列化对象的发送者和接收者都加载的类该对象是相对于序列兼容。如果接收者已经为对象提供了一个类,该对象的 serialVersionUID 与对应的发送者类的 serialVersionUID 不同,那么反序列化将导致 InvalidClassException。可序列化的类可以通过声明名为 serialVersionUID 的字段来明确声明自己的 serialVersionUID,该字段必须是 static, final, 且类型为 long

ANY-ACCESS-MODIFIER static final long serialVersionUID = 1L;

如何使类符合序列化条件

要保持对象,相应的类必须实现 java.io.Serializable 接口。

import java.io.Serializable;

public class SerialClass implements Serializable {

    private static final long serialVersionUID = 1L;  
    private Date currentTime;
    
    public SerialClass() {
        currentTime = Calendar.getInstance().getTime();
    }

    public Date getCurrentTime() {
        return currentTime;
    }
}

如何将对象写入文件

现在我们需要将此对象写入文件系统。为此,我们使用 java.io.ObjectOutputStream

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

public class PersistSerialClass {

    public static void main(String [] args) {
        String filename = "time.ser";            
        SerialClass time = new SerialClass(); //We will write this object to file system.
        try {
            ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream(filename));
            out.writeObject(time); //Write byte stream to file system.
            out.close();
        } catch(IOException ex){
            ex.printStackTrace();
        }
     }
 }

如何从序列化状态重新创建对象

使用 java.io.ObjectInputStream 可以在以后从文件系统读取存储的对象,如下所示:

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

 public class ReadSerialClass {

    public static void main(String [] args) {
        String filename = "time.ser";    
        SerialClass time = null;

        try {
            ObjectInputStream in = new ObjectInputStream(new FileInputStream(filename));
            time = (SerialClass)in.readObject();
            in.close();
        } catch(IOException ex){
            ex.printStackTrace();
        } catch(ClassNotFoundException cnfe){
            cnfe.printStackTrace();
        }
        // print out restored time
        System.out.println("Restored time: " + time.getTime());
     }
 }

序列化类是二进制形式。如果类定义发生更改,则反序列化可能会出现问题: 有关详细信息,请参阅 Java 序列化规范的“序列化对象版本控制”一章

序列化对象序列化它作为根的整个对象图,并在存在循环图的情况下正确运行。提供了一种 reset() 方法来强制 ObjectOutputStream 忘记已经序列化的对象。

瞬态场 - 序列化