Reflection:查看版本 v2
由 mcst12345 于 2026-10-04 03:21 保存 · 2921 字节
'''Reflection'''(反射,<code>java.lang.reflect</code>)是在运行时获取类、字段、方法、构造器的信息并调用它们的机制。
== 常用 API ==
* <code>Class.forName</code>、<code>getDeclaredField</code>、<code>getDeclaredMethod</code>、<code>getDeclaredConstructor</code>
* <code>Field.get</code> / <code>Field.set</code>、<code>Method.invoke</code>、<code>Constructor.newInstance</code>
* <code>setAccessible(true)</code>:关闭访问检查,访问 private 成员
== 模块系统下的限制 ==
* Java 16 起默认强封装,Java 17 彻底强封装:对未开放(opens)的包调用 <code>setAccessible(true)</code> 会抛 <code>InaccessibleObjectException</code>。
* 可用 <code>--add-opens</code> 启动参数放开,或借助 [[Unsafe]]、[[MethodHandle]] 中的 <code>IMPL_LOOKUP</code> 绕过。
* <code>static final</code> 字段即使 <code>setAccessible(true)</code> 也不能用 <code>Field.set</code> 修改;Java 12 起 <code>Field</code> 的 <code>modifiers</code> 等字段被反射过滤,旧的“去掉 final 修饰符”写法失效。
== 在模组中 ==
* 運行時對於mc原版字段/方法需使用中間混淆名,或使用 <code>ObfuscationReflectionHelper</code> 自动映射。
* 反射调用有额外开销,热点代码可改用 [[MethodHandle]]。
* 例如通过反射取得 [[ServerLevel]] 的 <code>entityTickList</code>,即可直接操作 [[EntityTickList]]。
'''Reflection''' is a Java mechanism to access classes, methods, fields and their metadata at runtime without knowing what their are.
Before JPMS you can use reflection to access nearly everything: unfortunately you can't do that anymore since Java9+. The module system introduced more strict access control, that class A from module A cannot access class B in module B if B isn't declared as "opened" in module B event if B is public.
Fortunately there are workarounds to fuck up module system's access control.
== Commonly used APIs ==
* <code>Class.forName</code>、<code>getDeclaredField</code>、<code>getDeclaredMethod</code>、<code>getDeclaredConstructor</code> To obtain handles for class/field/method, Constructor can be considered an extension to Method.
* <code>Field.get</code> / <code>Field.set</code>、<code>Method.invoke</code>、<code>Constructor.newInstance</code> To actually invoke your handle.
* <code>setAccessible(true)</code> Tell JVM to ignore the private/protected access flag and do WTF you want.
== Notes ==
getDeclaredField, getDeclaredMethod, getDeclaredConstructor etc. returns cached/copied handles that can be spoofed. To get the true handles you can invoke getDeclaredField0, getDeclaredMethod0, getDeclaredConstructor0, etc.
Reflection is known to be suck at performance as it does much work automatically like boxing/unboxing and type cast. MethodHandle/VarHandle will be a better alternative if you know exactly what you need to invoke.