调用方法与访问字段
使用 Method.invoke 和 Field.set,并结合 setAccessible 调用私有方法、设置不可访问的字段
调用方法与访问字段 是 CoddyKit 上的免费 Java Academy 课时。 这是第 2 节课,共 4 节。 你可以在下方免费阅读本课时的完整内容 — 然后在浏览器中使用内置代码编辑器和全天候 AI 导师进行实践。 这是 Java Academy 学习路径的一部分,你的进度在网页和 CoddyKit 应用中同步。 Java Academy 课程共包含 4 节课。
setAccessible:绕过可见性限制
调用 field.setAccessible(true) 或 method.setAccessible(true) 可以绕过 Java 的访问控制。访问私有成员时必须这样做。在 Java 9 及更高版本中,还需要适当的模块访问权限。
Field f = User.class.getDeclaredField("name");
f.setAccessible(true);
User u = new User("Alice", 30);
System.out.println(f.get(u)); // "Alice"
f.set(u, "Bob"); // mutate the private field
System.out.println(u.getName()); // "Bob"读取字段值
请使用 field.get(instance) 读取任意字段值(基本类型值会被装箱)。对于静态字段,请将 null 作为实例传入。
Field f = MyClass.class.getDeclaredField("count");
f.setAccessible(true);
int count = (int) f.get(null); // static field → null instance设置字段值
请使用 field.set(instance, value) 写入字段。值的类型必须匹配,或能够自动拆箱。现代 JVM 中,通过反射设置 final 字段属于未定义行为。
Field nameField = User.class.getDeclaredField("name");
nameField.setAccessible(true);
nameField.set(user, "Charlie");通过反射调用方法
获取一个 Method 对象,调用 setAccessible(true),然后使用 method.invoke(instance, args...) 调用它。返回值的类型是 Object。
Method greet = User.class.getDeclaredMethod("greet", String.class);
greet.setAccessible(true);
String result = (String) greet.invoke(user, "World");
System.out.println(result);处理 InvocationTargetException
如果被调用的方法抛出异常,反射会将其包装在 InvocationTargetException 中。请使用 getCause() 将其解包。
try {
method.invoke(obj, args);
} catch (InvocationTargetException e) {
Throwable cause = e.getCause();
System.err.println("Method threw: " + cause.getMessage());
} catch (IllegalAccessException | NoSuchMethodException e) {
System.err.println("Reflection error: " + e.getMessage());
}调用静态方法
调用静态方法时,请将 null 作为实例参数传入。
Method parseInt = Integer.class.getDeclaredMethod("parseInt", String.class);
int value = (int) parseInt.invoke(null, "42"); // null = static
System.out.println(value); // 42通过构造器创建实例
获取一个 Constructor;对于私有构造器,调用 setAccessible(true),然后调用 newInstance(args...)。
Constructor<User> ctor = User.class.getDeclaredConstructor(String.class, int.class);
ctor.setAccessible(true);
User u = ctor.newInstance("Diana", 28);
System.out.println(u);框架中的反射:Spring DI
Spring 使用反射实例化 Bean 并注入依赖。它会调用私有构造器并设置私有字段,以连接应用程序上下文。
Java 9 及更高版本中的模块访问
在 Java 9 及更高版本中,模块默认会限制 setAccessible。如果类位于命名模块中,可能需要开放其包:--add-opens java.base/java.lang=ALL-UNNAMED。
// JVM flag to open a package for reflection:
// --add-opens java.base/java.lang=ALL-UNNAMEDMethodHandles:更快的替代方案
MethodHandles.lookup().findVirtual() 提供反射式方法调用;经过即时编译优化后,其性能接近直接调用。它适合用于对性能要求高的库代码。
MethodHandles.Lookup lookup = MethodHandles.privateLookupIn(User.class, MethodHandles.lookup());
MethodHandle handle = lookup.findVirtual(User.class, "getName", MethodType.methodType(String.class));
String name = (String) handle.invoke(user);反射的最佳实践
缓存 Field/Method 对象——不要在高频循环中反复获取它们。将反射封装在服务类中。请考虑使用 MethodHandles 来提升性能。在可能的情况下,优先使用接口而不是反射。
快速检查
通过反射调用的方法抛出异常时,哪个异常会包装其原因?
回顾
使用 setAccessible(true) 访问私有成员。通过 method.invoke() 调用方法。解包 InvocationTargetException。缓存反射对象。在高频路径中优先使用 MethodHandles。
常见问题解答
「调用方法与访问字段」课时是免费的吗?
是的 — 「调用方法与访问字段」的完整文本可在网页上免费阅读。要进行交互式练习(内置代码编辑器和全天候 AI 导师)并解锁 Java Academy 课程的其余内容,请升级到 CoddyKit PRO。 Java Academy 课程共包含 4 节课。
「调用方法与访问字段」这节课中我会学到什么?
使用 Method.invoke 和 Field.set,并结合 setAccessible 调用私有方法、设置不可访问的字段 你通过在浏览器中直接运行的动手代码来练习 Java Academy,全天候 AI 导师会在你学习这节课的过程中回答你的问题。
学习 Java Academy 需要有经验吗?
无需任何先前经验。CoddyKit 上的 Java Academy 课程适合初学者到高级学习者,你可以从这里开始或从头开始,按照自己的节奏学习。 这是第 2 节课,共 4 节。
「调用方法与访问字段」课时需要多长时间?
大多数 CoddyKit 课程大约需要 5–10 分钟。每节课都很精短且互动,所以你能稳步进步,并在网页和应用中从离开的地方继续。
我能在这节 Java Academy 课中编写并运行代码吗?
能。每节 Java Academy 课都包含内置代码编辑器,你可以在浏览器中直接编写并运行真实代码,并获得即时 AI 反馈 — 无需本地设置。