目录基本概念为什么需要序列化?
Java 序列化实现1. 实现 Serializable 接口
2. 序列化操作
重要概念
1. serialVersionUID
2. transient 关键字
3. 自定义序列化
4. Externalizable 接口序列化的注意事项安全问题性能问题其他序列化框架1. JSON 序列化(Jackson)
2. Protocol Buffers
3. 其他框架
最佳实践总结基本概念序列化(Serialization)
:将对象的状态信息转换为可以存储或传输的形式(如字节流)的过程。
反序列化(Deserialization)
:从字节流中恢复对象的过程,是序列化的逆操作。
为什么需要序列化?
持久化存储:将对象保存到文件或数据库中网络传输:在网络上传输对象(如分布式系统、RPC调用)
进程间通信:在不同进程之间传递对象缓存:将对象缓存到内存或磁盘Java 序列化实现1. 实现 Serializable 接口import java.io.*;
// 可序列化的类public class Person implements Serializable {// 序列化版本号(强烈建议)
private static final long serialVersionUID = 1L;
private String name;private int age;
// transient 关键字:该字段不会被序列化private transient String password;
public Person(String name, int age, String password) {this.name = name;this.age = age;this.password = password;}
// getters and setters...
@Override public String toString() {return "Person{name='" + name + "', age=" + age + ", password='" + password + "'}";}}
2. 序列化操作
public class SerializationDemo {public static void serialize(Object obj, String filename) throws IOException {try (ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(filename))) {oos.writeObject(obj);System.out.println("对象序列化成功!");}}
public static Object deserialize(String filename) throws IOException, ClassNotFoundException {try (ObjectInputStream ois = new ObjectInputStream(new FileInputStream(filename))) {Object obj = ois.readObject();System.out.println("对象反序列化成功!");return obj;}}
public static void main(String[] args) {Person person = new Person("张三", 25, "123456");
try {// 序列化serialize(person, "person.ser");
// 反序列化Person deserializedPerson = (Person) deserialize("person.ser");System.out.println("反序列化后的对象: " + deserializedPerson);// 输出: Person{name='张三', age=25, password='null'} (password为null因为transient)
} catch (IOException | ClassNotFoundException e) {e.printStackTrace();}}}重要概念
1. serialVersionUID
private static final long serialVersionUID = 1L;用于标识类的版本如果类结构发生变化,serialVersionUID 也应改变如果不指定,JVM 会自动生成,但可能导致反序列化失败2. transient 关键字private transient String password; // 不会被序列化标记不需要序列化的字段,如:敏感信息(密码)
临时数据可重新计算的数据
3. 自定义序列化
public class CustomPerson implements Serializable {private String name;private int age;
// 自定义序列化方法private void writeObject(ObjectOutputStream oos) throws IOException {oos.defaultWriteObject(); // 默认序列化// 可以添加额外的序列化逻辑}
// 自定义反序列化方法private void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException {ois.defaultReadObject(); // 默认反序列化// 可以添加额外的反序列化逻辑}}4. Externalizable 接口import java.io.*;
public class ExternalizablePerson implements Externalizable {private String name;private int age;
// 必须有无参构造器public ExternalizablePerson() {}
public ExternalizablePerson(String name, int age) {this.name = name;this.age = age;}
@Override public void writeExternal(ObjectOutput out) throws IOException {out.writeObject(name);out.writeInt(age);}
@Override public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {name = (String) in.readObject();age = in.readInt();}}序列化的注意事项安全问题// 反序列化可能存在安全风险Object obj = ois.readObject(); // 可能执行恶意代码反序列化不受信任的数据可能导致代码执行建议使用白名单验证类考虑使用安全的序列化框架性能问题Java 原生序列化性能较差生成的字节流较大考虑使用其他序列化框架其他序列化框架1. JSON 序列化(Jackson)
import com.fasterxml.jackson.databind.ObjectMapper;
ObjectMapper mapper = new ObjectMapper();
// 序列化为 JSON String json = mapper.writeValueAsString(person);
// 从 JSON 反序列化Person person = mapper.readValue(json, Person.class);2. Protocol Buffers// 需要定义 .proto 文件// 高性能、跨语言、体积小
3. 其他框架
Gson:Google 的 JSON 库Fastjson:阿里巴巴的 JSON 库Kryo:高性能二进制序列化Hessian:二进制序列化协议最佳实践始终声明 serialVersionUID使用 transient 保护敏感数据考虑使用 JSON 等文本格式替代二进制序列化反序列化时进行数据验证对于性能敏感场景,使用专业序列化框架避免序列化不可信的数据不要序列化包含资源(如文件句柄、数据库连接)的对象总结特性Java 原生序列化JSON 序列化Protocol Buffers可读性二进制文本二进制性能一般较慢很快跨语言仅 Java支持支持体积较大较大很小使用场景Java 内部使用Web API高性能场景选择合适的序列化方式取决于具体的使用场景、性能要求和跨语言需求。
以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。
您可能感兴趣的文章:Java解决Jackson反序列化字段名不匹配问题java反序列化serialVersionUID不一致问题及解决Java JDBC 反序列化实战案例Java中JSON格式反序列化为Map且保证存取顺序一致的问题Java中JSON字符串反序列化(动态泛型) Java中序列化与反序列化的定义及代码示例Java反射与Fastjson的危险反序列化详解
