Mmc秒杀圈百科 

隐藏类:查看版本 v1

由 朝武芳乃 于 2026-10-04 02:03 保存 · 2621 字节
''本条基于 Java 17(Minecraft 1.20.1 所用版本),HotSpot 行为以 JDK 17 为准。'' '''隐藏类'''(Hidden Class,JEP 371,Java 15 引入)是用 <code>MethodHandles.Lookup.defineHiddenClass</code> 定义的类,专供框架在运行时生成、且只被框架自己使用。Lambda 表达式生成的类(形如 <code>Foo$$Lambda$14/0x...</code>)和 LambdaForm 类都是隐藏类。 == 性质 == * '''不可按名字发现''':<code>Class.forName</code>、<code>ClassLoader.loadClass</code> 找不到它,其他类的常量池也无法按名字链接到它,只能通过 <code>defineHiddenClass</code> 返回的 <code>Class</code> 对象使用。 * 类名形如 <code>包名.类名/0x0000000800c01000</code>,斜杠后的后缀由 JVM 生成;<code>Class.isHidden()</code> 返回 true。 * 默认不被其定义类加载器强引用,不可达时可以单独卸载;传入 <code>ClassOption.STRONG</code> 则与类加载器同生命周期。 * 栈帧默认不出现在堆栈信息里。 * '''不可被 [[Instrumentation]] 修改''':HotSpot 的 <code>is_modifiable_class</code> 对隐藏类返回 false,所以 <code>isModifiableClass</code> 为 false,[[redefineClasses]] 和 [[retransformClasses]] 都不能用。 * '''定义时不触发 ClassFileLoadHook''':HotSpot 创建类时会跳过隐藏类的这一步,已注册的 transformer 看不到它的字节码。 == 用 Unsafe 去除标志 == 隐藏状态只是 Klass 里的一个标志位,用 [[Unsafe]] 把它清掉,类就会被当作普通类,上面两个限制随之解除。思路与 [[klassptr]] 相同:先拿到 <code>Class</code> 对象对应的 Klass 指针,再按偏移读写其中的标志。 * JDK 17:标志是 <code>Klass::_access_flags</code> 中的 <code>JVM_ACC_IS_HIDDEN_CLASS</code>(0x04000000)。 * 较新的 JDK 已经把它挪到 <code>KlassFlags</code> 里,位置和位值都不同。 == 注意事项 == * '''依赖 JDK 内部布局''':Klass 的字段偏移、标志位置随 JDK 版本、构建和压缩类指针等变化,写死偏移很脆弱,一般要按版本从 HotSpot 导出的 VMStructs 信息里定位。 * 偏移或位写错会直接让 JVM 崩溃,而不是抛异常。 * 清除后只是让它“看起来像普通类”:<code>Class.isHidden()</code> 变为 false,但类名里仍带 <code>/0x...</code> 后缀,依赖该标志的其他行为(栈帧显示、卸载等)也会跟着改变。 * 能被 retransform / redefine 之后,仍受“只能改方法体、不能增删成员”的限制。 参见:[[Unsafe]]、[[klassptr]]、[[MethodHandle]]、[[Instrumentation]]

其他版本