java原来是defaultReadObject()
在 Java 中,如果你定义了一个类实现了 java.io.Serializable,你可以选择是否定义 private void readObject(ObjectInputStream in) 方法。
这个方法用于 自定义反序列化逻辑。但它是可选的:
private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
// 你可以先调用默认反序列化
in.defaultReadObject();
// 然后做额外处理,比如解密、校验等
}
🧠 Java反序列化原理解析
Java反序列化(deserialization)就是把一段 序列化后的二进制数据(通常来自 .ser 文件、网络流等)还原成 Java 对象。
✅ 反序列化的大致流程:
读取魔数 + 版本号(stream header)
每个 .ser 文件的前几个字节包含一个魔数,用来识别这是 Java 的序列化流(0xAC ED 开头)。
后面跟着版本号(目前固定是 0x00 05)。
检查类的全限定名
序列化数据中包含对象所属类的类名(例如 com.example.User)。
JVM 会使用这个类名,在当前 classpath 中查找是否有这个类的定义。
检查 serialVersionUID 是否匹配
这是用于版本控制的一个长整型字段。
如果二进制流里的 serialVersionUID 和你本地类定义中的不一致,会抛出 InvalidClassException。
如果类本地没有定义这个值,Java 会自动计算一个(不建议依赖这个特性,易出错)。
创建对象实例(绕过构造函数)
JVM 使用反射机制 不调用构造函数,而是通过底层手段直接创建对象实例。
所有非 static、非 transient 的字段都会被填充。
恢复对象状态
从序列化数据中提取每个字段的值,按照本地类的字段类型填充到对象中。
❌ 如果类不存在或不匹配会发生什么?
情况结果类不存在(找不到类)抛出 ClassNotFoundExceptionserialVersionUID 不匹配抛出 InvalidClassException字段类型不同抛出类型相关异常或数据错乱
🔍 PHP 反序列化机制简要说明
PHP 的序列化格式是一种字符串格式(不是二进制),例如:
O:4:"User":2:{s:4:"name";s:5:"Alice";s:3:"age";i:18;}
这表示:
一个名为 User 的类(O 表示对象,后面的数字是类名长度)。
有两个属性:name 和 age。
✅ PHP 反序列化时的行为:
会先检查本地是否存在这个类:
如果类存在,就正常反序列化,恢复对象状态。
如果本地没有这个类定义:
PHP 会创建一个名为 __PHP_Incomplete_Class 的对象,用来占位。
不会报错,但这个对象功能受限(不能正常调用方法)。
🔗 所以不像 Java,PHP 允许反序列化一个本地没有定义的类,不会直接报错。