Java序列化和反序列化教程:从入门到实践
1. 序列化的概念与作用
在 Java 编程领域中,序列化(Serialization)是指将对象的状态转换为字节流的过程,以便将其存储在文件中或通过网络进行传输。反序列化(Deserialization)则是将字节流转换回对象的过程。序列化的主要作用是使对象的状态可以永久保存或传输给其他程序。
1.1. 序列化的优势
通过序列化,我们可以将 Java 对象存储在磁盘上、通过网络传输到远程机器,或者在进程之间共享对象状态。这种灵活性使得序列化成为现代分布式系统和持久化存储的重要组成部分。
1.2. 序列化的应用场景
- 持久化对象状态:通过序列化,可以将对象的状态保存在磁盘上,以便在程序重新启动时恢复对象。
 - 远程通信:对象可以通过序列化和反序列化在网络上进行传输,实现分布式计算和远程调用。
 - 缓存机制:序列化对象可以用于缓存系统,提高读取性能。
 - 对象复制:通过序列化和反序列化可以实现对象的深度复制,避免对象引用的问题。
 
2. Java 的序列化机制
Java 提供了一种标准的序列化机制,即将希望序列化的类实现 java.io.Serializable 接口。这个接口是一个标记接口,没有任何方法需要实现。实现了 Serializable 接口的类可以将其对象转换为字节流,从而进行序列化操作。
2.1. serialVersionUID
在进行序列化和反序列化时,Java 虚拟机需要确定类的序列化版本是否与流中的版本匹配。为了确保版本匹配,我们可以为类提供一个称为 serialVersionUID 的唯一标识符。当类的版本与流中的版本不匹配时,会抛出 InvalidClassException。
private static final long serialVersionUID = 1L;
 
  2.2. transient 关键字
有时候,某些对象的字段不需要进行序列化,我们可以使用 transient 关键字修饰这些字段。被 transient 修饰的字段在序列化时会被忽略。
private transient String password;
 
  3. 实现序列化与反序列化
3.1. 实现 Serializable 接口
为了使一个类可以序列化,我们需要让它实现 Serializable 接口。下面是一个示例:
import java.io.Serializable;
public class Student implements Serializable {
    private static final long serialVersionUID = 1L;
    
    private String name;
    private int age;
    
    // 省略构造方法和其他成员方法
}
 
  3.2. 序列化对象
要将一个对象序列化为字节流,我们可以使用 ObjectOutputStream 类:
import java.io.FileOutputStream;
import java.io.ObjectOutputStream;
public class Test {
    public static void main(String[] args) {
        Student student = new Student("张三", 20);
        try {
            FileOutputStream fileOut = new FileOutputStream("student.ser");
            ObjectOutputStream out = new ObjectOutputStream(fileOut);
            out.writeObject(student);
            out.close();
            fileOut.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
 
  3.3. 反序列化对象
将字节流转换回对象的过程称为反序列化。要进行反序列化,我们可以使用 ObjectInputStream 类:
import java.io.FileInputStream;
import java.io.ObjectInputStream;
public class Test {
    public static void main(String[] args) {
        Student student = null;
        try {
            FileInputStream fileIn = new FileInputStream("student.ser");
            ObjectInputStream in = new ObjectInputStream(fileIn);
            student = (Student) in.readObject();
            in.close();
            fileIn.close();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
		// 使用反序列化后的对象
        System.out.println("学生姓名:" + student.getName());
        System.out.println("学生年龄:" + student.getAge());
    }
}
 
  4. 序列化与反序列化的案例应用
4.1. 对象的持久化存储
通过序列化,我们可以将对象的状态存储在文件中,以便在程序重新启动时恢复对象。下面是一个简单的例子:
import java.io.*;
public class PersistentStorageExample {
    public static void main(String[] args) {
        Student student = new Student("李四", 18);
        
        try {
            FileOutputStream fileOut = new FileOutputStream("student.ser");
            ObjectOutputStream out = new ObjectOutputStream(fileOut);
            out.writeObject(student);
            out.close();
            fileOut.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
        
        // 重新读取对象
        try {
            FileInputStream fileIn = new FileInputStream("student.ser");
            ObjectInputStream in = new ObjectInputStream(fileIn);
            Student savedStudent = (Student) in.readObject();
            in.close();
            fileIn.close();
            
            System.out.println("学生姓名:" + savedStudent.getName());
            System.out.println("学生年龄:" + savedStudent.getAge());
        } catch (IOException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }
}
 
  4.2. 对象的远程传输
通过序列化,我们可以将对象以字节流的形式在网络上进行传输。这在分布式系统和远程方法调用中非常有用。
先做了解,后面的教程我们会将网络传输。
import java.io.*;
import java.net.Socket;
public class RemoteTransferExample {
    public static void main(String[] args) {
        Student student = new Student("王五", 22);
        String hostname = "localhost";
        int port = 12345;
        
        try {
            Socket socket = new Socket(hostname, port);
            
            OutputStream outputStream = socket.getOutputStream();
            ObjectOutputStream out = new ObjectOutputStream(outputStream);
            out.writeObject(student);
            
            InputStream inputStream = socket.getInputStream();
            BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));
            String response = reader.readLine();
            System.out.println("服务器返回消息:" + response);
            
            out.close();
            outputStream.close();
            socket.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
 
  在上述代码中,我们将一个 Student 对象通过网络传输到远程服务器,并接收服务器的响应。
5. 总结
通过本篇文章,我们了解了 Java 中的序列化机制及其应用场景。我们学习了如何实现序列化和反序列化,以及序列化对象的持久化存储和远程传输。序列化是 Java 编程中非常重要的一部分,它为分布式系统、持久化存储和数据传输提供了便捷的方法。