Mmc秒杀圈百科 

隐藏类

由 朝武芳乃管理员 最后编辑于 2026-10-04 02:03 · 当前版本 v1
标签:技术正经内容
你尚未登录。登录后可编辑本页与创建新条目 —— 登录 或 注册账号。

本条基于 Java 17(Minecraft 1.20.1 所用版本),HotSpot 行为以 JDK 17 为准。

隐藏类(Hidden Class,JEP 371,Java 15 引入)是用 MethodHandles.Lookup.defineHiddenClass 定义的类,专供框架在运行时生成、且只被框架自己使用。Lambda 表达式生成的类(形如 Foo$$Lambda$14/0x...)和 LambdaForm 类都是隐藏类。

性质

  • 不可按名字发现:Class.forName、ClassLoader.loadClass 找不到它,其他类的常量池也无法按名字链接到它,只能通过 defineHiddenClass 返回的 Class 对象使用。
  • 类名形如 包名.类名/0x0000000800c01000,斜杠后的后缀由 JVM 生成;Class.isHidden() 返回 true。
  • 默认不被其定义类加载器强引用,不可达时可以单独卸载;传入 ClassOption.STRONG 则与类加载器同生命周期。
  • 栈帧默认不出现在堆栈信息里。
  • 不可被 Instrumentation 修改:HotSpot 的 is_modifiable_class 对隐藏类返回 false,所以 isModifiableClass 为 false,redefineClasses 和 retransformClasses 都不能用。
  • 定义时不触发 ClassFileLoadHook:HotSpot 创建类时会跳过隐藏类的这一步,已注册的 transformer 看不到它的字节码。

用 Unsafe 去除标志

隐藏状态只是 Klass 里的一个标志位,用 Unsafe 把它清掉,类就会被当作普通类,上面两个限制随之解除。思路与 klassptr 相同:先拿到 Class 对象对应的 Klass 指针,再按偏移读写其中的标志。

  • JDK 17:标志是 Klass::_access_flags 中的 JVM_ACC_IS_HIDDEN_CLASS(0x04000000)。
  • 较新的 JDK 已经把它挪到 KlassFlags 里,位置和位值都不同。

注意事项

  • 依赖 JDK 内部布局:Klass 的字段偏移、标志位置随 JDK 版本、构建和压缩类指针等变化,写死偏移很脆弱,一般要按版本从 HotSpot 导出的 VMStructs 信息里定位。
  • 偏移或位写错会直接让 JVM 崩溃,而不是抛异常。
  • 清除后只是让它“看起来像普通类”:Class.isHidden() 变为 false,但类名里仍带 /0x... 后缀,依赖该标志的其他行为(栈帧显示、卸载等)也会跟着改变。
  • 能被 retransform / redefine 之后,仍受“只能改方法体、不能增删成员”的限制。

参见:Unsafe、klassptr、MethodHandle、Instrumentation

你对本条的回应 · 登录后可表态

讨论(0)

讨论不进入条目正文的版本历史,适合提出修改建议、指出问题或补充来源。
还没有人讨论这个条目。你可以提出修改建议、指出问题或补充来源。

发表话题

请先 登录 后再参与讨论。