Java反射
Java反射机制深度解析:动态编程的强大武器
什么是反射?
Java反射(Reflection)是Java语言的一个强大特性,它允许程序在运行时检查和修改类、方法、字段等结构的行为。简单来说,反射就是"程序能够观察和修改自身行为"的能力。
反射的核心类
Java反射API主要包含以下几个核心类:
Class- 代表类的实体Field- 代表类的成员变量Method- 代表类的方法Constructor- 代表类的构造方法Modifier- 提供对修饰符的访问
获取Class对象的三种方式
// 方式1:通过类名.class
Class<?> clazz1 = String.class;
// 方式2:通过对象.getClass()
String str = "Hello";
Class<?> clazz2 = str.getClass();
// 方式3:通过Class.forName()
Class<?> clazz3 = Class.forName("java.lang.String");
反射的基本操作
1. 获取类的信息
public class ReflectionDemo {
public static void main(String[] args) throws Exception {
Class<?> clazz = Class.forName("java.util.ArrayList");
// 获取类名
System.out.println("类名: " + clazz.getName());
System.out.println("简单类名: " + clazz.getSimpleName());
// 获取包名
System.out.println("包名: " + clazz.getPackage().getName());
// 获取修饰符
int modifiers = clazz.getModifiers();
System.out.println("修饰符: " + Modifier.toString(modifiers));
// 获取父类
System.out.println("父类: " + clazz.getSuperclass().getName());
// 获取实现的接口
Class<?>[] interfaces = clazz.getInterfaces();
for (Class<?> interfaceClass : interfaces) {
System.out.println("接口: " + interfaceClass.getName());
}
}
}
2. 操作字段(Field)
public class FieldDemo {
private String privateField = "私有字段";
public String publicField = "公有字段";
public static void main(String[] args) throws Exception {
Class<?> clazz = FieldDemo.class;
FieldDemo instance = new FieldDemo();
// 获取所有字段(包括私有字段)
Field[] fields = clazz.getDeclaredFields();
for (Field field : fields) {
System.out.println("字段名: " + field.getName());
System.out.println("字段类型: " + field.getType().getName());
// 设置可访问性(对于私有字段)
field.setAccessible(true);
// 获取字段值
Object value = field.get(instance);
System.out.println("字段值: " + value);
// 修改字段值
if (field.getName().equals("privateField")) {
field.set(instance, "修改后的私有字段");
}
}
System.out.println("修改后的privateField: " + instance.privateField);
}
}
3. 操作方法(Method)
public class MethodDemo {
private void privateMethod(String message) {
System.out.println("私有方法被调用: " + message);
}
public void publicMethod(int number) {
System.out.println("公有方法被调用: " + number);
}
public static void main(String[] args) throws Exception {
Class<?> clazz = MethodDemo.class;
MethodDemo instance = new MethodDemo();
// 获取所有方法
Method[] methods = clazz.getDeclaredMethods();
for (Method method : methods) {
System.out.println("方法名: " + method.getName());
System.out.println("返回类型: " + method.getReturnType().getName());
// 获取参数类型
Class<?>[] paramTypes = method.getParameterTypes();
for (Class<?> paramType : paramTypes) {
System.out.println("参数类型: " + paramType.getName());
}
// 调用方法
method.setAccessible(true);
if (method.getName().equals("privateMethod")) {
method.invoke(instance, "Hello Reflection");
} else if (method.getName().equals("publicMethod")) {
method.invoke(instance, 42);
}
}
}
}
4. 操作构造方法(Constructor)
public class ConstructorDemo {
private String name;
private int age;
public ConstructorDemo() {
this.name = "默认名称";
this.age = 0;
}
public ConstructorDemo(String name, int age) {
this.name = name;
this.age = age;
}
public static void main(String[] args) throws Exception {
Class<?> clazz = ConstructorDemo.class;
// 获取所有构造方法
Constructor<?>[] constructors = clazz.getDeclaredConstructors();
for (Constructor<?> constructor : constructors) {
System.out.println("构造方法: " + constructor.getName());
// 获取参数类型
Class<?>[] paramTypes = constructor.getParameterTypes();
for (Class<?> paramType : paramTypes) {
System.out.println("参数类型: " + paramType.getName());
}
}
// 使用无参构造方法创建实例
Constructor<?> defaultConstructor = clazz.getDeclaredConstructor();
ConstructorDemo instance1 = (ConstructorDemo) defaultConstructor.newInstance();
System.out.println("无参构造实例: " + instance1.name + ", " + instance1.age);
// 使用有参构造方法创建实例
Constructor<?> paramConstructor = clazz.getDeclaredConstructor(String.class, int.class);
ConstructorDemo instance2 = (ConstructorDemo) paramConstructor.newInstance("张三", 25);
System.out.println("有参构造实例: " + instance2.name + ", " + instance2.age);
}
}
反射的常见应用场景
1. 动态代理
interface UserService {
void addUser(String name);
void deleteUser(String name);
}
class UserServiceImpl implements UserService {
public void addUser(String name) {
System.out.println("添加用户: " + name);
}
public void deleteUser(String name) {
System.out.println("删除用户: " + name);
}
}
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("方法调用前: " + method.getName());
Object result = method.invoke(target, args);
System.out.println("方法调用后: " + method.getName());
return result;
}
}
public class DynamicProxyDemo {
public static void main(String[] args) {
UserService realService = new UserServiceImpl();
UserService proxy = (UserService) Proxy.newProxyInstance(
UserService.class.getClassLoader(),
new Class[]{UserService.class},
new DynamicProxyHandler(realService)
);
proxy.addUser("Alice");
proxy.deleteUser("Bob");
}
}
2. 注解处理器
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
@interface Loggable {
String value() default "";
}
class AnnotationProcessor {
public void processAnnotations(Object obj) throws Exception {
Class<?> clazz = obj.getClass();
Method[] methods = clazz.getDeclaredMethods();
for (Method method : methods) {
if (method.isAnnotationPresent(Loggable.class)) {
Loggable annotation = method.getAnnotation(Loggable.class);
String message = annotation.value();
System.out.println("执行带注解的方法: " + method.getName());
if (!message.isEmpty()) {
System.out.println("注解信息: " + message);
}
method.invoke(obj);
}
}
}
}
class TestClass {
@Loggable("这是一个测试方法")
public void testMethod() {
System.out.println("测试方法被执行");
}
public void normalMethod() {
System.out.println("普通方法被执行");
}
}
3. 配置文件驱动的对象创建
public class ConfigDrivenFactory {
public static Object createObject(String className) throws Exception {
Class<?> clazz = Class.forName(className);
return clazz.getDeclaredConstructor().newInstance();
}
public static Object createObject(String className, Object... args) throws Exception {
Class<?> clazz = Class.forName(className);
Class<?>[] paramTypes = new Class[args.length];
for (int i = 0; i < args.length; i++) {
paramTypes[i] = args[i].getClass();
}
Constructor<?> constructor = clazz.getDeclaredConstructor(paramTypes);
return constructor.newInstance(args);
}
}
反射的性能考虑
反射虽然强大,但也有一些性能开销:
- 性能开销:反射调用比直接调用慢
- 安全性限制:需要处理安全检查
- 代码可读性:反射代码相对难以理解
- 类型安全:编译时类型检查较弱
性能优化建议
public class ReflectionPerformance {
// 缓存Method对象以避免重复查找
private static final Map<String, Method> methodCache = new HashMap<>();
public static Object invokeCachedMethod(Object obj, String methodName, Object... args)
throws Exception {
String key = obj.getClass().getName() + "#" + methodName;
Method method = methodCache.get(key);
if (method == null) {
Class<?>[] paramTypes = new Class[args.length];
for (int i = 0; i < args.length; i++) {
paramTypes[i] = args[i].getClass();
}
method = obj.getClass().getDeclaredMethod(methodName, paramTypes);
method.setAccessible(true);
methodCache.put(key, method);
}
return method.invoke(obj, args);
}
}
反射的最佳实践
- 适度使用:只在真正需要动态性时使用反射
- 缓存结果:缓存Class、Method、Field等对象
- 异常处理:妥善处理各种反射异常
- 安全性:注意访问控制和安全限制
- 文档注释:为反射代码添加详细注释
总结
Java反射是一个强大的工具,它为Java程序提供了运行时 introspection 和 manipulation 的能力。虽然反射带来了性能开销和复杂性,但在框架开发、动态代理、注解处理等场景中,它是不可或缺的。
关键要点:
- 反射允许程序在运行时检查类和对象
- 可以动态调用方法、访问字段、创建实例
- 广泛应用于框架、代理、注解处理等场景
- 需要注意性能优化和安全性
- 适度使用,避免过度复杂化代码
掌握反射机制,将让你在Java开发中拥有更强大的武器,能够编写出更加灵活和动态的应用程序。
本文来自博客园,作者:路口偶然遇见你,转载请注明原文链接:https://www.cnblogs.com/wzy/p/19072760

浙公网安备 33010602011771号