本文目录导读:

在Java中,反序列化对象是将之前通过序列化保存的字节流重新恢复为Java对象的过程,以下是完整的案例说明:
基本反序列化示例
首先创建一个可序列化的类
import java.io.Serializable;
public class Person implements Serializable {
// 序列化版本号,建议显式声明
private static final long serialVersionUID = 1L;
private String name;
private int age;
private String email;
// transient关键字修饰的字段不会被序列化
private transient String password;
public Person(String name, int age, String email, String password) {
this.name = name;
this.age = age;
this.email = email;
this.password = password;
}
// getter和setter方法
public String getName() { return name; }
public int getAge() { return age; }
public String getEmail() { return email; }
public String getPassword() { return password; }
@Override
public String toString() {
return "Person{name='" + name + "', age=" + age +
", email='" + email + "', password='" + password + "'}";
}
}
反序列化方法
import java.io.FileInputStream;
import java.io.ObjectInputStream;
import java.io.IOException;
public class DeserializationExample {
public static void main(String[] args) {
String filename = "person.ser";
// 从文件反序列化对象
Person person = deserializeFromFile(filename);
if (person != null) {
System.out.println("反序列化成功!");
System.out.println(person);
// password是transient,所以会为null
System.out.println("Password (transient): " + person.getPassword());
}
}
/**
* 从文件反序列化对象
*/
public static Person deserializeFromFile(String filename) {
Person person = null;
try (FileInputStream fileIn = new FileInputStream(filename);
ObjectInputStream in = new ObjectInputStream(fileIn)) {
// 读取对象
person = (Person) in.readObject();
} catch (IOException | ClassNotFoundException e) {
e.printStackTrace();
System.err.println("反序列化失败: " + e.getMessage());
}
return person;
}
}
多种反序列化方式
import java.io.*;
import java.util.Base64;
public class MultipleDeserializationMethods {
/**
* 从文件反序列化
*/
public static Object fromFile(String filePath) throws Exception {
try (FileInputStream fis = new FileInputStream(filePath);
ObjectInputStream ois = new ObjectInputStream(fis)) {
return ois.readObject();
}
}
/**
* 从字节数组反序列化
*/
public static Object fromByteArray(byte[] data) throws Exception {
try (ByteArrayInputStream bais = new ByteArrayInputStream(data);
ObjectInputStream ois = new ObjectInputStream(bais)) {
return ois.readObject();
}
}
/**
* 从Base64字符串反序列化
*/
public static Object fromBase64String(String base64Str) throws Exception {
byte[] data = Base64.getDecoder().decode(base64Str);
return fromByteArray(data);
}
/**
* 从输入流反序列化
*/
public static Object fromInputStream(InputStream inputStream) throws Exception {
try (ObjectInputStream ois = new ObjectInputStream(inputStream)) {
return ois.readObject();
}
}
// 使用示例
public static void main(String[] args) {
try {
// 1. 从文件
Person person1 = (Person) fromFile("person.ser");
// 2. 从字节数组
byte[] data = /* 获取字节数组 */;
Person person2 = (Person) fromByteArray(data);
// 3. 从Base64字符串
String base64Str = /* 获取Base64字符串 */;
Person person3 = (Person) fromBase64String(base64Str);
} catch (Exception e) {
e.printStackTrace();
}
}
}
安全性考虑 - 验证反序列化
import java.io.*;
import java.util.Arrays;
import java.util.List;
public class SafeDeserialization {
// 白名单 - 允许反序列化的类
private static final List<String> WHITE_LIST = Arrays.asList(
"Person",
"java.lang.String",
"java.util.ArrayList"
);
/**
* 安全的反序列化(使用白名单)
*/
public static Object safeDeserialize(byte[] data) throws Exception {
try (ByteArrayInputStream bais = new ByteArrayInputStream(data);
SafeObjectInputStream sois = new SafeObjectInputStream(bais)) {
return sois.readObject();
}
}
/**
* 自定义ObjectInputStream,实现白名单验证
*/
static class SafeObjectInputStream extends ObjectInputStream {
public SafeObjectInputStream(InputStream in) throws IOException {
super(in);
}
@Override
protected Class<?> resolveClass(ObjectStreamClass desc)
throws IOException, ClassNotFoundException {
String className = desc.getName();
// 检查是否在白名单中
if (!isWhitelisted(className)) {
throw new SecurityException("反序列化被拒绝: " + className);
}
return super.resolveClass(desc);
}
private boolean isWhitelisted(String className) {
for (String allowed : WHITE_LIST) {
if (className.contains(allowed)) {
return true;
}
}
return false;
}
}
}
完整示例 - 序列化和反序列化
import java.io.*;
public class CompleteExample {
public static void main(String[] args) {
// 1. 创建原始对象
Person originalPerson = new Person("张三", 25, "zhangsan@example.com", "123456");
System.out.println("原始对象: " + originalPerson);
// 2. 序列化到文件
try (FileOutputStream fos = new FileOutputStream("person.ser");
ObjectOutputStream oos = new ObjectOutputStream(fos)) {
oos.writeObject(originalPerson);
System.out.println("序列化成功!");
} catch (IOException e) {
e.printStackTrace();
}
// 3. 从文件反序列化
try (FileInputStream fis = new FileInputStream("person.ser");
ObjectInputStream ois = new ObjectInputStream(fis)) {
Person deserializedPerson = (Person) ois.readObject();
System.out.println("反序列化后的对象: " + deserializedPerson);
// 验证反序列化结果
System.out.println("\n验证结果:");
System.out.println("Name: " + deserializedPerson.getName());
System.out.println("Age: " + deserializedPerson.getAge());
System.out.println("Email: " + deserializedPerson.getEmail());
// transient字段为null
System.out.println("Password (应为null): " + deserializedPerson.getPassword());
} catch (IOException | ClassNotFoundException e) {
e.printStackTrace();
}
}
}
注意事项
- 版本控制:始终声明
serialVersionUID - 安全性:反序列化可能存在安全风险,建议使用白名单验证
- 异常处理:处理好 IOException 和 ClassNotFoundException
- transient关键字:标记的字段不会被序列化/反序列化
- 资源管理:使用 try-with-resources 自动关闭流
常见问题解决
// 当serialVersionUID不匹配时的处理
public class CompatiblePerson implements Serializable {
// 使用默认值,允许向后兼容
private static final long serialVersionUID = 1L;
// 添加新字段时的处理
private String newField;
// 自定义反序列化逻辑
private void readObject(ObjectInputStream in)
throws IOException, ClassNotFoundException {
// 执行默认反序列化
in.defaultReadObject();
// 执行自定义逻辑
if (newField == null) {
newField = "默认值";
}
}
}
这就是Java反序列化的完整案例,涵盖了基本用法、多种方式、安全性考虑和最佳实践。