跳转到内容

Java ObjectInputStream

来自代码酷

模板:Note

Java ObjectInputStream 全面指南[编辑 | 编辑源代码]

ObjectInputStream 是Java I/O系统中用于反序列化对象的核心类,它属于java.io包,与ObjectOutputStream配合使用实现对象的持久化存储和网络传输。

核心概念[编辑 | 编辑源代码]

ObjectInputStream的主要功能是从输入流中读取被序列化的Java对象,并将其还原为内存中的对象实例。这个过程称为反序列化(Deserialization)。

序列化与反序列化[编辑 | 编辑源代码]

graph LR A[内存对象] -->|序列化| B[字节序列] B -->|反序列化| A

数学表示: deserialize:byte[]Object

基础用法[编辑 | 编辑源代码]

类声明[编辑 | 编辑源代码]

public class ObjectInputStream
    extends InputStream 
    implements ObjectInput, ObjectStreamConstants

基本示例[编辑 | 编辑源代码]

从文件读取对象:

try (FileInputStream fis = new FileInputStream("data.obj");
     ObjectInputStream ois = new ObjectInputStream(fis)) {
    
    // 读取对象
    Object obj = ois.readObject();
    
    if (obj instanceof Person) {
        Person p = (Person) obj;
        System.out.println("反序列化对象: " + p);
    }
} catch (IOException | ClassNotFoundException e) {
    e.printStackTrace();
}

假设Person类已实现Serializable接口,输出可能是:

反序列化对象: Person{name='John', age=30}

关键方法详解[编辑 | 编辑源代码]

方法 描述
readObject() 读取并反序列化对象
readInt() 读取32位整数
readUTF() 读取UTF-8格式字符串
defaultReadObject() 使用默认机制反序列化非静态/瞬态字段
readFields() 读取序列化字段

自定义反序列化[编辑 | 编辑源代码]

通过实现private void readObject(ObjectInputStream ois)方法:

private void readObject(ObjectInputStream ois) 
    throws IOException, ClassNotFoundException {
    
    // 默认反序列化
    ois.defaultReadObject();
    
    // 自定义处理
    this.timestamp = System.currentTimeMillis();
}

安全注意事项[编辑 | 编辑源代码]

重要警告:反序列化不受信任的数据可能导致严重安全问题:

  • 远程代码执行(RCE)
  • 拒绝服务攻击(DoS)

防护措施: 1. 使用ObjectInputFilter(Java 9+) 2. 验证序列化UID 3. 避免反序列化不可信来源数据

过滤器示例[编辑 | 编辑源代码]

ObjectInputFilter filter = info -> {
    if (info.serialClass() != null && 
        info.serialClass().getName().equals("com.example.Person")) {
        return ObjectInputFilter.Status.ALLOWED;
    }
    return ObjectInputFilter.Status.REJECTED;
};

ois.setObjectInputFilter(filter);

高级特性[编辑 | 编辑源代码]

版本控制[编辑 | 编辑源代码]

使用serialVersionUID保持版本兼容:

private static final long serialVersionUID = 1L;

替代机制[编辑 | 编辑源代码]

对于复杂场景,可考虑:

  • Externalizable接口
  • JSON/XML序列化库(如Jackson、Gson)

实际应用案例[编辑 | 编辑源代码]

分布式系统通信[编辑 | 编辑源代码]

sequenceDiagram Client->>Server: 序列化对象(通过ObjectOutputStream) Server->>Server: 处理请求 Server->>Client: 返回序列化响应(通过ObjectInputStream)

持久化存储[编辑 | 编辑源代码]

// 保存游戏状态
public void saveGame(Player player, String filename) {
    try (ObjectOutputStream oos = new ObjectOutputStream(
        new FileOutputStream(filename))) {
        oos.writeObject(player);
    } catch (IOException e) {
        System.err.println("保存失败: " + e.getMessage());
    }
}

// 加载游戏
public Player loadGame(String filename) {
    try (ObjectInputStream ois = new ObjectInputStream(
        new FileInputStream(filename))) {
        return (Player) ois.readObject();
    } catch (IOException | ClassNotFoundException e) {
        System.err.println("加载失败: " + e.getMessage());
        return null;
    }
}

常见问题[编辑 | 编辑源代码]

反序列化失败原因[编辑 | 编辑源代码]

1. 类未实现Serializable 2. serialVersionUID不匹配 3. 类定义发生不兼容变更 4. 流数据损坏

性能优化[编辑 | 编辑源代码]

  • 使用缓冲流(BufferedInputStream
  • 批量处理对象
  • 考虑替代序列化方案(如Protocol Buffers)

最佳实践[编辑 | 编辑源代码]

1. 始终显式声明serialVersionUID 2. 对敏感字段使用transient 3. 实现readObject()时保持防御性编程 4. 在finally块中关闭流或使用try-with-resources

模板:Tip

参见[编辑 | 编辑源代码]