Java 反射详解
反射基础概念
什么是反射?
反射(Reflection)是Java在运行时:
- 检查类、接口、字段和方法的能力
- 动态创建对象、调用方法、访问和修改字段
- 绕过访问权限检查(通过setAccessible(true))
反射的核心原理
// Java类加载过程
源代码(.java) → 编译 → 字节码(.class) → 类加载器 → 方法区(存储类信息)
↓
反射通过Class对象访问
反射核心API
1. 获取Class对象的三种方式
// 方式1: 类名.class
Class<String> stringClass = String.class;
// 方式2: 对象.getClass()
String str = "hello";
Class<?> clazz = str.getClass();
// 方式3: Class.forName()
Class<?> clazz = Class.forName("java.lang.String");
2. 类信息获取
Class<?> clazz = String.class;
// 获取类名
String className = clazz.getName(); // java.lang.String
String simpleName = clazz.getSimpleName(); // String
// 获取修饰符
int modifiers = clazz.getModifiers();
Modifier.isPublic(modifiers); // 检查是否为public
// 获取包信息
Package pkg = clazz.getPackage();
// 获取父类
Class<?> superClass = clazz.getSuperclass();
// 获取实现的接口
Class<?>[] interfaces = clazz.getInterfaces();
3. 字段操作
Class<?> clazz = User.class;
// 获取所有公共字段(包括继承的)
Field[] publicFields = clazz.getFields();
// 获取所有字段(不包括继承的)
Field[] allFields = clazz.getDeclaredFields();
// 获取特定字段
Field nameField = clazz.getDeclaredField("name");
// 字段操作
User user = new User();
nameField.setAccessible(true); // 突破私有访问限制
nameField.set(user, "张三"); // 设置字段值
Object value = nameField.get(user); // 获取字段值
4. 方法操作
Class<?> clazz = User.class;
// 获取所有公共方法
Method[] publicMethods = clazz.getMethods();
// 获取所有声明的方法
Method[] allMethods = clazz.getDeclaredMethods();
// 获取特定方法
Method setNameMethod = clazz.getMethod("setName", String.class);
// 方法调用
User user = new User();
setNameMethod.invoke(user, "李四"); // 调用方法
5. 构造器操作
Class<?> clazz = User.class;
// 获取所有公共构造器
Constructor<?>[] publicConstructors = clazz.getConstructors();
// 获取所有构造器
Constructor<?>[] allConstructors = clazz.getDeclaredConstructors();
// 获取特定构造器
Constructor<?> constructor = clazz.getDeclaredConstructor(String.class, int.class);
// 创建实例
constructor.setAccessible(true); // 如果是私有构造器
User user = (User) constructor.newInstance("王五", 25);
反射应用场景
1. 框架开发
// Spring-like 依赖注入示例
public class SimpleContainer {
private Map<String, Object> beans = new HashMap<>();
public void registerBean(String name, Class<?> clazz) throws Exception {
// 查找@Autowired注解的字段并自动注入
Object instance = clazz.newInstance();
Field[] fields = clazz.getDeclaredFields();
for (Field field : fields) {
if (field.isAnnotationPresent(Autowired.class)) {
field.setAccessible(true);
Object dependency = beans.get(field.getType().getSimpleName());
field.set(instance, dependency);
}
}
beans.put(name, instance);
}
}
2. 动态代理
public class DynamicProxyHandler implements InvocationHandler {
private Object target;
public DynamicProxyHandler(Object target) {
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// 前置处理
System.out.println("Before method: " + method.getName());
// 调用实际方法
Object result = method.invoke(target, args);
// 后置处理
System.out.println("After method: " + method.getName());
return result;
}
public static Object createProxy(Object target) {
return Proxy.newProxyInstance(
target.getClass().getClassLoader(),
target.getClass().getInterfaces(),
new DynamicProxyHandler(target)
);
}
}
3. 注解处理器
// 自定义注解
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface JsonField {
String value() default "";
}
// 注解处理器
public class JsonSerializer {
public static String toJson(Object obj) throws Exception {
StringBuilder json = new StringBuilder("{");
Class<?> clazz = obj.getClass();
Field[] fields = clazz.getDeclaredFields();
for (Field field : fields) {
if (field.isAnnotationPresent(JsonField.class)) {
field.setAccessible(true);
JsonField annotation = field.getAnnotation(JsonField.class);
String fieldName = annotation.value().isEmpty() ?
field.getName() : annotation.value();
Object value = field.get(obj);
json.append(String.format("\"%s\":\"%s\",", fieldName, value));
}
}
if (json.charAt(json.length()-1) == ',') {
json.deleteCharAt(json.length()-1);
}
json.append("}");
return json.toString();
}
}
4. 数据库ORM框架
// 简单的ORM映射
public class SimpleORM {
public static <T> T mapResultSetToObject(ResultSet rs, Class<T> clazz) throws Exception {
T instance = clazz.newInstance();
ResultSetMetaData metaData = rs.getMetaData();
int columnCount = metaData.getColumnCount();
for (int i = 1; i <= columnCount; i++) {
String columnName = metaData.getColumnName(i);
Object columnValue = rs.getObject(i);
// 根据列名找到对应字段
Field field = findField(clazz, columnName);
if (field != null) {
field.setAccessible(true);
field.set(instance, columnValue);
}
}
return instance;
}
private static Field findField(Class<?> clazz, String columnName) {
Field[] fields = clazz.getDeclaredFields();
for (Field field : fields) {
if (field.getName().equalsIgnoreCase(columnName)) {
return field;
}
}
return null;
}
}
代码示例
完整示例:反射工具类
public class ReflectionUtils {
/**
* 创建对象实例
*/
public static Object newInstance(Class<?> clazz, Object... args) throws Exception {
if (args == null || args.length == 0) {
return clazz.newInstance();
}
Class<?>[] parameterTypes = new Class[args.length];
for (int i = 0; i < args.length; i++) {
parameterTypes[i] = args[i].getClass();
}
Constructor<?> constructor = clazz.getDeclaredConstructor(parameterTypes);
constructor.setAccessible(true);
return constructor.newInstance(args);
}
/**
* 调用方法
*/
public static Object invokeMethod(Object obj, String methodName, Object... args) throws Exception {
Class<?>[] parameterTypes = new Class[args.length];
for (int i = 0; i < args.length; i++) {
parameterTypes[i] = args[i].getClass();
}
Method method = obj.getClass().getDeclaredMethod(methodName, parameterTypes);
method.setAccessible(true);
return method.invoke(obj, args);
}
/**
* 设置字段值
*/
public static void setFieldValue(Object obj, String fieldName, Object value) throws Exception {
Field field = obj.getClass().getDeclaredField(fieldName);
field.setAccessible(true);
field.set(obj, value);
}
/**
* 获取字段值
*/
public static Object getFieldValue(Object obj, String fieldName) throws Exception {
Field field = obj.getClass().getDeclaredField(fieldName);
field.setAccessible(true);
return field.get(obj);
}
/**
* 获取所有字段信息(包括父类)
*/
public static List<Field> getAllFields(Class<?> clazz) {
List<Field> fields = new ArrayList<>();
Class<?> currentClass = clazz;
while (currentClass != null && currentClass != Object.class) {
fields.addAll(Arrays.asList(currentClass.getDeclaredFields()));
currentClass = currentClass.getSuperclass();
}
return fields;
}
}
// 测试类
class User {
private String name;
private int age;
public User() {}
public User(String name, int age) {
this.name = name;
this.age = age;
}
private String getInfo() {
return "User: " + name + ", Age: " + age;
}
// getter/setter省略
}
// 测试代码
public class ReflectionTest {
public static void main(String[] args) throws Exception {
// 创建实例
User user = (User) ReflectionUtils.newInstance(User.class, "张三", 25);
// 调用私有方法
String info = (String) ReflectionUtils.invokeMethod(user, "getInfo");
System.out.println(info);
// 访问私有字段
ReflectionUtils.setFieldValue(user, "name", "李四");
String name = (String) ReflectionUtils.getFieldValue(user, "name");
System.out.println("修改后的名字: " + name);
}
}
注意事项
1. 性能问题
// 错误的用法 - 重复获取Method对象
for (int i = 0; i < 1000; i++) {
Method method = clazz.getMethod("methodName");
method.invoke(obj);
}
// 正确的用法 - 缓存Method对象
Method method = clazz.getMethod("methodName");
for (int i = 0; i < 1000; i++) {
method.invoke(obj);
}
2. 安全限制
// 安全检查会降低性能
Method method = clazz.getDeclaredMethod("privateMethod");
method.setAccessible(true); // 关闭安全检查可提升性能
// 但要注意:这会破坏封装性,应谨慎使用
3. 类型安全
// 反射绕过了编译期类型检查
Method method = clazz.getMethod("setName", String.class);
method.invoke(obj, 123); // 运行时错误:参数类型不匹配
// 建议:进行参数类型验证
Object[] args = {123};
Class<?>[] parameterTypes = method.getParameterTypes();
if (!parameterTypes[0].isInstance(args[0])) {
throw new IllegalArgumentException("参数类型不匹配");
}
4. 异常处理
try {
Method method = clazz.getDeclaredMethod("methodName");
method.invoke(obj);
} catch (NoSuchMethodException e) {
// 方法不存在
System.err.println("方法不存在: " + e.getMessage());
} catch (IllegalAccessException e) {
// 访问权限不足
System.err.println("访问被拒绝: " + e.getMessage());
} catch (InvocationTargetException e) {
// 被调用方法抛出异常
Throwable targetException = e.getTargetException();
System.err.println("方法执行异常: " + targetException.getMessage());
}
性能优化
1. 缓存反射对象
public class ReflectionCache {
private static final Map<String, Method> METHOD_CACHE = new ConcurrentHashMap<>();
private static final Map<String, Field> FIELD_CACHE = new ConcurrentHashMap<>();
private static final Map<String, Constructor<?>> CONSTRUCTOR_CACHE = new ConcurrentHashMap<>();
public static Method getMethod(Class<?> clazz, String methodName, Class<?>... parameterTypes)
throws NoSuchMethodException {
String key = generateKey(clazz, methodName, parameterTypes);
return METHOD_CACHE.computeIfAbsent(key, k -> {
try {
Method method = clazz.getDeclaredMethod(methodName, parameterTypes);
method.setAccessible(true);
return method;
} catch (NoSuchMethodException e) {
throw new RuntimeException(e);
}
});
}
private static String generateKey(Class<?> clazz, String name, Class<?>... parameterTypes) {
StringBuilder key = new StringBuilder(clazz.getName()).append(".").append(name);
for (Class<?> paramType : parameterTypes) {
key.append("_").append(paramType.getName());
}
return key.toString();
}
}
2. 使用MethodHandle(Java 7+)
public class MethodHandleDemo {
public static void methodHandleCall() throws Throwable {
MethodHandles.Lookup lookup = MethodHandles.lookup();
MethodType methodType = MethodType.methodType(String.class, String.class);
MethodHandle methodHandle = lookup.findVirtual(String.class, "concat", methodType);
String result = (String) methodHandle.invokeExact("Hello", " World");
System.out.println(result); // 输出: Hello World
}
}
总结
反射的优点
- 灵活性:运行时动态操作类
- 通用性:编写通用框架和工具
- 扩展性:支持插件架构和动态加载
反射的缺点
- 性能开销:比直接调用慢
- 安全限制:可能破坏封装性
- 复杂度高:代码难以理解和维护
- 类型安全:绕过了编译期检查
最佳实践
- 尽量避免在性能敏感的代码中使用反射
- 缓存反射对象以提高性能
- 做好异常处理和边界检查
- 考虑使用替代方案(如MethodHandle)
- 明确使用反射的目的,不要滥用
重要提醒:反射是强大的工具,但应该谨慎使用。在大多数业务开发中,应优先考虑面向接口编程和其他设计模式,而不是过度依赖反射。