objectstreamclass是java中表示类序列化描述符的核心类,包含类名、serialversionuid、字段列表(objectstreamfield)等元数据,用于反序列化时校验兼容性与字段匹配。

ObjectStreamClass 是什么
ObjectStreamClass 是 JVM 在反序列化过程中用来表示“类的序列化描述符”的核心类。它不等于 Class 对象本身,而是对某个实现了 Serializable 接口的类在序列化时所生成的元数据快照:包括类名、serialVersionUID、字段列表(ObjectStreamField)、是否为代理类、是否有自定义 readObject/writeObject 方法等。
反序列化时如何解析并构造 ObjectStreamClass
当 ObjectInputStream 调用 readClassDescriptor() 读取流中类描述信息时,会按协议解析出原始字节中的类标识(如类名、serialVersionUID、字段签名等),然后调用 ObjectStreamClass.initNonProxy() 构造本地对应的 ObjectStreamClass 实例。这个过程的关键点有:
- 先尝试通过 ObjectStreamClass.lookup(Class) 查找当前 JVM 中已加载的该类对应的描述符;若未命中,则新建一个,并递归初始化其超类的 ObjectStreamClass(直到找到最顶层未实现 Serializable 的父类)
- 构造时会检查本地 Class 是否与流中描述一致:类名必须相同;serialVersionUID 必须匹配(否则抛 InvalidClassException);字段类型冲突会直接报错(如流中是 String,本地是 int)
- 字段信息由 ObjectStreamField 数组承载,每个字段记录名称、类型签名、是否为 transient、是否为 static 等——这些不参与赋值,但决定反序列化时是否跳过该字段
字段匹配与兼容性逻辑(matchFields)
ObjectStreamClass 的 matchFields() 方法在 readOrdinaryObject 阶段被调用,用于比对流中字段与本地类字段的兼容性:
- 流中存在、本地不存在的字段:标记为“忽略”,不报错,也不赋值
- 本地存在、流中不存在的字段:保留默认值(如 int=0、Object=null),不会被覆盖
- 同名但类型不一致(如流中是 long,本地是 int):直接抛 java.io.InvalidClassException,拒绝反序列化
- 字段顺序无关,只依赖名称和签名;transient 和 static 字段天然不参与序列化,也不会出现在字段列表中
反射在此过程中的真实角色
反射并不用于“动态加载类”(Class.forName 已完成),而是用于:
- 查找并缓存目标类的无参构造器(用于 new 实例,不执行构造逻辑)
- 获取私有方法如 readObject、readResolve、writeReplace 的 Method 对象,以便后续回调
- 访问 private 字段进行设值(通过 setAccessible(true) 绕过访问控制),但仅限于非 transient / 非 static 的可序列化字段
注意:反序列化创建对象时不调用任何构造方法(包括无参构造),而是通过 Unsafe.allocateInstance 或 JVM 内部机制绕过构造器直接分配内存——只有在调用 readObject 或 readExternal 时,才可能间接触发构造逻辑。











