Java中的序列化(Serialization)和反序列化(Deserialization)是用于在对象之间进行数据传输和持久化的机制。序列化是将对象转换为字节流的过程,而反序列化则是将字节流重新转换为对象的过程。

序列化的原理:

1. 将对象转换为字节流: 在序列化过程中,Java虚拟机会将对象的状态(即成员变量的值)转换为字节流。这涉及将对象的类、成员变量及其值写入到输出流中。

2. 保存对象状态: 序列化后的字节流包含了对象的类信息以及成员变量的值,可以被保存到文件、数据库或通过网络传输。

3. 对象的版本控制: 序列化机制允许开发者在对象的类发生变化时控制版本信息,以确保反序列化过程的兼容性。

反序列化的原理:

1. 从字节流中恢复对象: 在反序列化过程中,Java虚拟机会从输入流中读取字节,并将其转换回对象的状态。这涉及根据字节流中的类信息重新创建对象,并设置其成员变量的值。

2. 验证类的兼容性: 在反序列化过程中,Java虚拟机会验证字节流中的类信息与当前类是否兼容,以确保反序列化的对象与序列化时的类是一致的。

一个简单案例:

假设有一个简单的Java类Person:

import java.io.Serializable;

public class Person implements Serializable {  //person示例
       private String name;
       private int age;

       public Person(String name, int age) {  //构造函数
              this.name = name;
              this.age = age;
       }

       public String getName() {
              return name;
       }

       public int getAge() {
             return age;
       }
}

序列化示例:

import java.io.*;

public class SerializationDemo {  //序列化示例
    public static void main(String[] args) {
        
        Person person = new Person("Alice", 30);  //创建一个person对象

        try {
            FileOutputStream fileOut = new FileOutputStream("person.ser"); //创建文件输出流对象, 用于将序列化后的字节流保存在person.ser文件中
            ObjectOutputStream out = new ObjectOutputStream(fileOut);  //创建对象输出流对象, 用于将对象序列化为字节流  --> 使用文件输出流对象fileOut将序列化后的字节流保存在person.ser文件中
            out.writeObject(person); //指定将person对象序列化
            out.close(); //关闭对象输出流对象
            fileOut.close();  //关闭文件输出流对象
            System.out.println("Serialized data is saved in person.ser"); //输出提示序列化结束
        } catch (IOException e) {
            e.printStackTrace(); //报错提示
        }
    }
}

反序列化示例:

import java.io.*;

public class DeserializationDemo {  //反序列化示例
    public static void main(String[] args) {
        Person person = null; //声明一个person对象
        try {
            FileInputStream fileIn = new FileInputStream("person.ser"); // 创建一个文件输入流对象, 用于从序列化后的字节流文件person.ser中读取字节数据
            ObjectInputStream in = new ObjectInputStream(fileIn); // 创建对象输入流对象,使用文件输入流对象fileIn从序列化后的字节流文件person.ser中读取字节数据 ---> 将读取的字节数据还原为对象
            person = (Person) in.readObject(); // 将反序列化返回的对象转换为person对象格式
            in.close(); // 关闭对象输入流对象
            fileIn.close();  // 关闭文件输入流对象
        } catch (IOException | ClassNotFoundException e) {
            e.printStackTrace(); // 报错提示
        }

        // Accessing the deserialized object
        if (person != null) { // 输出person
            System.out.println("Name: " + person.getName());
            System.out.println("Age: " + person.getAge());
        }
    }
}
在这个示例中,Person对象被序列化并保存到文件person.ser中,然后从文件中读取并反序列化为一个新的Person对象。
至于反序列化漏洞,请移步另一篇文章 初步认识Java反序列化漏洞