constant_utf8_info采用modified utf-8编码,空字符\u0000编码为0xc0 0x80,需手动处理;其长度字段为2字节无符号short,表示字节数而非字符数。

常量池中 CONSTANT_Utf8_info 的实际字节布局和编码陷阱
Java class 文件里的 CONSTANT_Utf8_info 不是标准 UTF-8,而是“modified UTF-8”:空字符 \u0000 被编码为 0xC0 0x80,而 ASCII 字符(0x01–0x7F)仍用单字节。读取时若直接用 new String(bytes, "UTF-8") 解码,会把 0xC0 0x80 当作非法序列抛 MalformedInputException。
- 解析时必须手动处理
0xC0 0x80→\u0000,其余按 UTF-8 解码;JDK 自带的DataInputStream.readUTF()可复用,但它读的是“Java modified UTF-8”,且只适用于 class 文件中以两字节长度开头的字符串(即CONSTANT_Utf8_info的格式) - 常见错误:用
Files.readString(path, StandardCharsets.UTF_8)直接读 class 文件中的 Utf8 字段 —— 这会跳过长度前缀、忽略修改规则,必然失败 - 注意:class 文件中
CONSTANT_Utf8_info的长度字段是无符号 short(2 字节),表示后续字节数,不是字符数;一个中文字符可能占 3 字节,但长度字段只计 3
CONSTANT_Integer_info 和 CONSTANT_Float_info 的字节序与类型混淆
这两个常量类型都占 5 个字节:1 字节 tag + 4 字节值,且值都是 big-endian。但它们在运行时常量池里被当作不同语义对待——CONSTANT_Integer_info 是整型字面量,CONSTANT_Float_info 是浮点字面量,哪怕二进制完全一样(比如 0x3F800000 在 Integer 中是 1065353216,在 Float 中是 1.0)。
- 解析时不能只看 tag 就认为“4 字节就是 int”;必须严格按 tag 分支处理:tag == 3 →
CONSTANT_Integer_info→ByteBuffer.getInt();tag == 4 →CONSTANT_Float_info→ByteBuffer.getFloat() - 容易踩坑:把
CONSTANT_Float_info的 4 字节当成 int 解析后强转 float,会得到完全错误的值(例如0x3F800000当 int 是 1065353216,转 float 是 1.065353216E9) - 兼容性注意:JVM 规范要求所有数值常量都用 big-endian,不依赖 host 平台字节序;手写解析器务必用
ByteBuffer.order(ByteOrder.BIG_ENDIAN)
CONSTANT_Class_info 的 name_index 指向的是 Utf8,不是类名字符串本身
CONSTANT_Class_info 结构只有两个字段:tag(=7)和 name_index(2 字节),它本身不存类名,只是个指针。真正类名藏在另一个 CONSTANT_Utf8_info 条目里,由 name_index 索引过去。
- 解析时必须做两次查表:先读
name_index,再用该值作为下标去常量池数组里取对应CONSTANT_Utf8_info条目,最后解码其字节内容 - 常见错误:把
name_index当成类名偏移或直接当字符串用;或者忽略常量池索引从 1 开始(第 0 项无效),导致数组越界或读错条目 - 路径风格注意:class 文件中类名用
/分隔,如java/lang/Object,不是.;反编译工具显示的java.lang.Object是展示层转换,原始常量池里永远是斜杠
常量池索引溢出和解析顺序对 CONSTANT_Methodref_info 的影响
CONSTANT_Methodref_info(tag = 10)含三个索引:class_index、name_and_type_index,后者又指向一个 CONSTANT_NameAndType_info,里面再含两个索引:name_index 和 descriptor_index。四层嵌套,任意一级索引越界或指向非法 tag,都会让整个方法引用失效。
立即学习“Java免费学习笔记(深入)”;
- 必须逐级验证:先确认
class_index指向CONSTANT_Class_info,再确认name_and_type_index指向CONSTANT_NameAndType_info,再分别验证其内部两个索引是否指向CONSTANT_Utf8_info - 容易忽略:class 文件规范允许常量池中存在“未使用”的条目(比如
CONSTANT_Long_info和CONSTANT_Double_info占两个槽位,后一槽无效),所以索引不能简单等于数组下标;需按实际条目数动态计算有效索引范围 - 性能提示:全量预解析常量池比边用边查快,尤其对频繁反射或字节码分析场景;但首次加载 class 时若只关心某个方法,可延迟解析相关链路,避免冗余开销









