1. Java 反射机制实战:通过 Class 对象深入理解
1.1 获取 Class 对象的多种方式
在 Java 反射机制实战中,Class 对象是获取类信息的入口。你可以通过不同方式得到它,例如使用 Class.forName、类字面量 .class、以及对象实例的 getClass() 方法。
Class.forName 支持动态加载外部类,是实现插件机制的基础。下面的示例展示了三种常见的获取方式,以及它们在不同场景中的应用。
// 方式1:通过类字面量获取 Class 对象
Class> cls1 = String.class;// 方式2:通过 Class.forName 动态加载
Class> cls2 = Class.forName("java.lang.String");// 方式3:通过对象实例获取
String s = "hello";
Class> cls3 = s.getClass();
1.2 解析 Class 对象的核心信息
获取到 Class 对象后,可以提取所有关键信息:类名、包、父类、实现的接口、修饰符等。getName、getPackage、getSuperclass、getInterfaces、getModifiers 都是常用方法。
通过这些信息,可以在运行时动态做出决定,例如根据接口来选择实现、或根据修饰符进行权限检查。
Class> cls = Class.forName("java.util.ArrayList");
System.out.println("Name: " + cls.getName());
System.out.println("Package: " + cls.getPackage().getName());
System.out.println("Superclass: " + cls.getSuperclass().getName());Class>[] interfaces = cls.getInterfaces();
System.out.println("Interfaces: ");
for (Class> i : interfaces) {System.out.println(" " + i.getName());
}
2. 探索成员信息:字段、方法与构造器的反射操作
2.1 获取字段与方法的区别
在反射中,Field、Method、Constructor 等信息对象提供了访问成员的能力。需要注意的是,getDeclaredFields 与 getFields 的差异:前者返回类本身声明的所有字段(包括私有字段),后者只返回公有字段;类似的还有 getDeclaredMethods 与 getMethods。
通过理解这一区别,可以在实践中选择最小的视图和开销。下列代码说明了如何同时获取字段和方法的集合。
Class> cls = Class.forName("java.util.HashMap");
Field[] fields = cls.getDeclaredFields();
Method[] methods = cls.getDeclaredMethods();
System.out.println("Fields: " + fields.length + ", Methods: " + methods.length);
2.2 私有成员的访问与修改
反射默认情况下对非公有成员不可访问。要读取或修改 private 成员,需先打开访问控制检查:setAccessible(true)。这一操作应谨慎使用,因为它会破坏封装并可能导致安全风险,但在序列化、代理或框架内测等场景是常见手段。
下面的示例演示如何读取私有字段并修改其值。
class Demo {private int count = 0;
}
Demo d = new Demo();
Field f = Demo.class.getDeclaredField("count");
f.setAccessible(true);
Object value = f.get(d);
System.out.println("value = " + value);
f.set(d, 42);
2.3 构造器的获取与实例化
构造器是实例化对象的入口。可以通过 getDeclaredConstructors 或 getConstructors 获取构造器,然后用 newInstance 或新 API Constructor.newInstance 创建实例。
使用参数化构造器时,请通过 getDeclaredConstructor 指定参数类型,并调用 newInstance 创建对象。
class Person {private String name;private int age;public Person() {}private Person(String name, int age) { this.name = name; this.age = age; }
}
Constructor> ctor = Person.class.getDeclaredConstructor(String.class, int.class);
ctor.setAccessible(true);
Person p = (Person) ctor.newInstance("Alice", 30);
3. 动态调用与实例化的实战示例
3.1 动态实例化与字段注入
结合前面的知识,可以在运行时根据类名动态创建实例,并对字段进行注入。这在插件架构、序列化框架等场景非常有用。
下面的示例演示:根据类名创建实例并设置字段值。
String className = "com.example.Person";
Class> cls = Class.forName(className);
Constructor> ctor = cls.getDeclaredConstructor();
ctor.setAccessible(true);
Object obj = ctor.newInstance();// 注入字段
Field fName = cls.getDeclaredField("name");
fName.setAccessible(true);
fName.set(obj, "Bob");
System.out.println("Created: " + obj.getClass().getName());
3.2 动态方法调用
调用对象上的方法可以使用 Method 对象。支持对参数进行绑定,支持私有方法访问。

示例:调用一个名为 greet 的方法。
Method m = cls.getDeclaredMethod("greet", String.class);
m.setAccessible(true);
m.invoke(obj, "World");
3.3 使用反射实现简易的 JSON 反序列化示例
反射常用于将数据映射到对象的字段,尤其在没有绑定的序列化框架时。下面简单演示从键值对读取并设置字段。
Map map = new HashMap<>();
map.put("name", "Charlie");
map.put("age", 25);for (Map.Entry e : map.entrySet()) {Field f = cls.getDeclaredField(e.getKey());f.setAccessible(true);f.set(obj, e.getValue());
}
4. 性能优化与注意事项
4.1 缓存反射结果以提高吞吐
反射操作本身具有一定开销,尤其是 intermittent getDeclaredField、getMethod、newInstance 等。缓存 反射结果,是提升性能的最直接手段。你可以把 Field、Method、Constructor 等对象缓存到一个 ConcurrentHashMap 或自定义缓存中。
下例展示一个简化的缓存思路:先获取一次再复用。
class ReflectCache {private final Map, Field[]> fieldCache = new ConcurrentHashMap<>();public Field[] getFields(Class> cls) {return fieldCache.computeIfAbsent(cls, k -> k.getDeclaredFields());}
}
4.2 使用 MethodHandles 的替代方案与兼容性
在某些高吞吐场景,MethodHandles 提供接近原生调用的性能,与传统反射相比,执行成本更低。对于长期运行的热代码,可以在 静态初始化阶段 预解析并缓存方法句柄。
示例:通过 MethodHandles.Lookup 获取方法句柄并执行。
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;// 假设 cls 为目标类,methodName 为方法名
MethodHandles.Lookup lookup = MethodHandles.lookup();
MethodHandle mh = lookup.findVirtual(cls, "greet", MethodType.methodType(void.class, String.class));
mh.invokeExact(obj, "World");


