ObjectOutputStream写不出对象的主因是类未实现Serializable接口或含不可序列化字段,导致writeObject()抛NotSerializableException;必须确保类及所有非transient字段类型均实现该接口。

必须实现 Serializable 接口,且所有非 transient 字段类型也得可序列化,否则 writeObject() 会直接抛 NotSerializableException。
为什么 ObjectOutputStream 写不出对象?常见报错和硬性条件
最常卡在第一步:调用 writeObject() 时抛异常。这不是流没关好或路径错,而是类本身不满足序列化前提:
-
Person类没实现Serializable接口 → 报java.io.NotSerializableException: Person -
Person里有个字段是自定义类Address,但Address没实现Serializable→ 同样报NotSerializableException,错误信息里会明确写出那个不可序列化的字段类型 - 用了
static字段(它不属于对象实例)或transient字段(显式排除)→ 不会写入,但不会报错
注意:serialVersionUID 不是强制要求,但不加容易在类结构变动后反序列化失败,报 InvalidClassException。
ObjectOutputStream 的正确构造与资源管理
不能直接 new ObjectOutputStream,它必须包装一个底层字节流(如 FileOutputStream),且构造过程会自动写入头部协议数据(stream header),所以必须确保流未被提前关闭或复用。
- 必须用
new ObjectOutputStream(new FileOutputStream("xxx.ser")),不能把已打开的FileOutputStream传给多个ObjectOutputStream实例 - 如果要追加写入(append),不能直接复用同一个
ObjectOutputStream实例多次调用writeObject()—— 它会重复写 header,导致后续ObjectInputStream读取失败;需重写writeStreamHeader()或改用其他方式 - 推荐用 try-with-resources,但要注意:
ObjectOutputStream关闭时会连带关闭底层流;若需复用底层流(比如写多个对象到同一文件),得自己控制关闭时机
示例正确写法:
try (ObjectOutputStream oos = new ObjectOutputStream(
new FileOutputStream("data.ser"))) {
oos.writeObject(new Person("Alice", 30));
oos.writeObject(new Person("Bob", 25));
}
哪些字段会被真正持久化?transient 和 static 的实际行为
ObjectOutputStream 只序列化对象图中「可达的、非静态、非瞬态」的实例字段。这直接影响你存进去的东西能不能完整还原。
-
transient String token;→ 写入时跳过,反序列化后该字段为null(或其类型默认值) -
static int counter = 100;→ 根本不进对象图,序列化/反序列化全程无感知;反序列化后取的是当前 JVM 中该类的counter值(仍是 100,不是存盘时的值) - 父类字段:只要父类也实现了
Serializable,就会被递归序列化;否则抛异常(除非父类有无参构造且字段全transient)
别指望靠 transient 来“加密”敏感字段——它只是不存,不代表别人不能从内存或调试器里看到。
序列化后的文件能直接看吗?兼容性和跨语言问题
不能。生成的 .ser 文件是 Java 特有的二进制格式,含类名、字段签名、serialVersionUID、甚至 JVM 内部句柄等元数据。这意味着:
- 用文本编辑器打开只会看到乱码,
ObjectInputStream才能解析它 - 换 JDK 版本可能失败(尤其涉及内部类、Lambda 表达式时),因为编译器生成的类名或签名变了
- 跨语言(比如 Python 或 Go)几乎无法原生读取——Java 序列化不是通用协议,它不设计用于异构系统通信
如果需要跨语言或长期存储,优先考虑 JSON、Protobuf 或 Avro 等标准格式,而不是依赖 ObjectOutputStream 的二进制输出。


















