868 字
4 分钟
java序列化机制

1.什么是序列化

序列化是将对象的状态转换为欸字节流的过程,反序列化则是将字节流还原成对象。

在进行序列化时会将对象的逻辑状态保存下来,用于在反序列化时恢复对象

2.为什么需要序列化

在 java 中对象等信息保存在 jvm 中,包含引用,内存地址等信息,在进行跨 jvm 传输,环境的变化会导致原有的信息不在可用,内存地址等都发生了变化,所以在进行序列化的时候没有存储物理状态,只保存了逻辑状态用来恢复对象

3.java 中的序列化

3.1 Serializable 只是一个标记

public interface Serializable {
}

它没有任何方法,是一个标记接口(Marker Interface)。JVM 在序列化时会检查这个标记,没有实现它的类会直接抛出 NotSerializableException。真正干活的是 ObjectOutputStream 和 ObjectInputStream

3.2 序列化协议本身长什么样

用 hexdump 打开一个序列化后的文件,开头总是:

AC ED 00 05 ...
  • AC ED:魔数(STREAM_MAGIC),标识这是一个序列化流。

  • 00 05:版本号(STREAM_VERSION)。

后面跟着的是一系列类型标记字节,比如:

  • 73 (TC_OBJECT):表示接下来是一个对象。

  • 72 (TC_CLASSDESC):表示接下来是一个类描述符(类名、serialVersionUID、字段描述等)。

  • 78 (TC_ENDBLOCKDATA):自定义数据块结束

3.3 writeObject / readObject:真正的入口

默认情况下,ObjectOutputStream/ObjectInputStream 会通过反射自动读写一个类里所有非 transient、非 static 的字段。但如果类里自己定义了这两个私有方法:

private void writeObject(ObjectOutputStream out) throws IOException;
private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException;

JVM 就会调用这两个自定义方法,而不是走默认逻辑

3.4 readObject 的默认行为:defaultReadObject

即使自定义了 readObject,通常也会在里面调用:

private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
in.defaultReadObject(); // 走默认的字段读取逻辑
// 自定义的额外逻辑...
}

在学习反序列化链子时,很多时候 defaultReadObject()后就是值得关注的地方,因为在 defaultObject()对字段进行填充后往往就要对状态进行恢复,就会触发许多回调方法,就有可能被攻击者利用

3.5 readResolve / writeReplace:对象替换钩子

ANY-ACCESS-MODIFIER Object writeReplace() throws ObjectStreamException;
ANY-ACCESS-MODIFIER Object readResolve() throws ObjectStreamException;
  • writeReplace:序列化时,如果对象定义了这个方法,序列化流程会先调用它,用它的返回值替换掉原对象去序列化。

  • readResolve:反序列化重建出对象后,如果定义了这个方法,会用它的返回值替换掉刚重建出的对象,作为最终返回给调用者的对象。

3.7 Externalizable

java

public interface Externalizable extends Serializable {
void writeExternal(ObjectOutput out) throws IOException;
void readExternal(ObjectInput in) throws IOException, ClassNotFoundException;
}

区别于 Serializable 依赖反射自动读写字段,Externalizable 要求开发者完全手动实现读写逻辑,而且这两个方法是 public 的、在接口里显式声明的(不是约定,是真正的接口方法)。

  • 对于实现了Serializable但没有实现Externalizable 的类,反序列化重建对象时,不会调用该类自己的构造器,而是通过 JVM 内部的 native 机制(sun.reflect.ReflectionFactory#newConstructorForSerialization,底层最终依赖 Unsafe 分配内存)直接分配对象内存,跳过了包括无参构造器在内的所有构造逻辑。

  • 但如果父类没有实现Serializable,那么会调用到这个祖先类的无参构造器

java序列化机制
https://lab404.cn/posts/java-serialization/
作者
见山
发布于
2026-07-19
许可协议
CC BY-NC-SA 4.0