面试题答案
一键面试1. 自定义 writeObject
和 readObject
方法优化性能的原理
在Java序列化中,默认的序列化机制会序列化对象的所有非瞬态(transient
)字段。通过自定义 writeObject
和 readObject
方法,可以精细控制哪些字段需要被序列化,从而减少不必要的数据序列化。
2. 适用场景
- 大对象且部分字段无需序列化:当对象包含大的、无需在反序列化时重新构建的字段(如缓存数据、临时计算结果等)。例如,一个用于数据处理的类,它在运行过程中会计算并缓存一些中间结果,但这些中间结果在反序列化后不需要重新计算,且占用大量空间。
- 敏感信息不序列化:对于包含敏感信息(如密码、密钥等)的对象,这些信息在反序列化后可通过其他方式重新获取,且不应在序列化流中传输。
3. 示例
假设我们有一个 User
类,包含用户名、密码和一些临时缓存数据。密码不应该被序列化,缓存数据在反序列化后可以重新计算。
import java.io.*;
public class User implements Serializable {
private String username;
private transient String password; // 密码设为transient,防止默认序列化
private transient Map<String, Object> cache; // 缓存设为transient
public User(String username, String password) {
this.username = username;
this.password = password;
this.cache = new HashMap<>();
// 初始化缓存数据
}
// 自定义writeObject方法
private void writeObject(ObjectOutputStream out) throws IOException {
out.defaultWriteObject();
// 手动序列化需要的额外字段(如果有),这里密码不序列化
// 缓存数据也不序列化
}
// 自定义readObject方法
private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
in.defaultReadObject();
// 手动反序列化需要的额外字段(如果有)
// 重新计算或获取密码和缓存数据
this.password = "重新获取的密码";
this.cache = new HashMap<>();
// 重新初始化缓存数据
}
}
在上述示例中,writeObject
方法没有序列化 password
和 cache
字段,readObject
方法在反序列化后重新初始化了这些字段,从而减少了不必要的数据序列化,优化了性能。