Skip to content

反射

反射简介

什么是反射?

反射(Reflection)是 Java 的动态机制,允许在运行时检查和操作类、接口、属性、方法。

┌─────────────────────────────────────────────────────────────────┐
│                         反射的核心能力                            │
├─────────────────────────────────────────────────────────────────┤
│                                                                  │
│  1. 运行时了解对象类型(Class 对象)                              │
│  2. 运行时构造任意类的对象                                         │
│  3. 运行时调用任意对象的方法                                       │
│  4. 运行时访问/修改任意对象的属性                                  │
│  5. 运行时获取注解信息                                            │
│                                                                  │
└─────────────────────────────────────────────────────────────────┘

反射的应用场景

  • Spring IOC - 依赖注入、Bean 管理
  • Spring AOP - 动态代理
  • MyBatis - ORM 映射
  • JSON 序列化 - Gson/FastJSON
  • Spring MVC - 请求参数绑定
  • 单元测试 - JUnit/TestNG

Class 对象

获取 Class 的三种方式

java
public class ClassDemo {

    public static void main(String[] args) throws Exception {
        // 方式1:通过 .class
        Class<String> clazz1 = String.class;

        // 方式2:通过对象 .getClass()
        String str = "hello";
        Class<?> clazz2 = str.getClass();

        // 方式3:通过 Class.forName()
        Class<?> clazz3 = Class.forName("java.lang.String");

        // 三种方式获取的是同一个 Class 对象
        System.out.println(clazz1 == clazz2);  // true
        System.out.println(clazz2 == clazz3);  // true
    }
}

Class 常用方法

java
public class ClassMethods {

    public static void main(String[] args) {
        Class<String> clazz = String.class;

        // 获取类信息
        String name = clazz.getName();           // 全限定名:java.lang.String
        String simpleName = clazz.getSimpleName(); // 简单名:String
        Package pkg = clazz.getPackage();          // 包信息

        // 获取父类/接口
        Class<?> superClass = clazz.getSuperclass();  // java.lang.Object
        Class<?>[] interfaces = clazz.getInterfaces(); // 实现的所有接口

        // 获取修饰符
        int modifiers = clazz.getModifiers();
        boolean isPublic = Modifier.isPublic(modifiers);
        boolean isFinal = Modifier.isFinal(modifiers);
        boolean isAbstract = Modifier.isAbstract(modifiers);

        // 判断类型
        boolean isArray = clazz.isArray();
        boolean isEnum = clazz.isEnum();
        boolean isInterface = clazz.isInterface();
        boolean isPrimitive = clazz.isPrimitive();
    }
}

反射操作构造方法

获取构造方法

java
public class ConstructorReflection {

    public static void main(String[] args) throws Exception {
        Class<Person> clazz = Person.class;

        // 获取所有 public 构造方法
        Constructor<?>[] publicConstructors = clazz.getConstructors();

        // 获取所有构造方法(包括 private)
        Constructor<?>[] allConstructors = clazz.getDeclaredConstructors();

        // 获取指定构造方法
        Constructor<Person> defaultCon = clazz.getDeclaredConstructor();
        Constructor<Person> paramCon = clazz.getDeclaredConstructor(String.class, int.class);
    }
}

class Person {
    private String name;
    private int age;

    public Person() { }

    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }

    private Person(String name) {
        this.name = name;
    }
}

通过反射创建对象

java
public class CreateObject {

    public static void main(String[] args) throws Exception {
        Class<Person> clazz = Person.class;

        // 方式1:使用无参构造
        Person p1 = clazz.getDeclaredConstructor().newInstance();

        // 方式2:使用有参构造
        Constructor<Person> constructor = clazz.getDeclaredConstructor(String.class, int.class);
        Person p2 = constructor.newInstance("张三", 25);

        // 方式3:访问 private 构造方法
        Constructor<Person> privateCon = clazz.getDeclaredConstructor(String.class);
        privateCon.setAccessible(true);  // 跳过访问检查
        Person p3 = privateCon.newInstance("李四");
    }
}

反射操作成员变量

获取字段

java
public class FieldReflection {

    public static void main(String[] args) throws Exception {
        Class<Student> clazz = Student.class;
        Student student = clazz.getDeclaredConstructor().newInstance();

        // 获取所有 public 字段
        Field[] publicFields = clazz.getFields();

        // 获取所有字段(包括 private)
        Field[] allFields = clazz.getDeclaredFields();

        // 获取指定字段
        Field nameField = clazz.getDeclaredField("name");
        Field ageField = clazz.getDeclaredField("age");
    }
}

class Student {
    public String name;
    private int age;
    public static String school;  // 静态字段
    public final int grade = 1;  // 常量
}

读取/修改字段值

java
public class FieldAccess {

    public static void main(String[] args) throws Exception {
        Class<Student> clazz = Student.class;
        Student student = clazz.getDeclaredConstructor().newInstance();

        // 操作实例字段
        Field nameField = clazz.getDeclaredField("name");
        nameField.setAccessible(true);  // 设置可访问(跳过 private 检查)

        // 读取字段值
        nameField.set(student, "张三");
        String name = (String) nameField.get(student);
        System.out.println("姓名:" + name);

        // 操作私有字段
        Field ageField = clazz.getDeclaredField("age");
        ageField.setAccessible(true);
        ageField.setInt(student, 20);  // 直接设置 int 类型
        int age = ageField.getInt(student);
        System.out.println("年龄:" + age);

        // 操作静态字段
        Field schoolField = clazz.getDeclaredField("school");
        schoolField.set(null, "清华大学");  // 静态字段用 null
        String school = (String) schoolField.get(null);
        System.out.println("学校:" + school);
    }
}

反射操作方法

获取方法

java
public class MethodReflection {

    public static void main(String[] args) throws Exception {
        Class<Calculator> clazz = Calculator.class;

        // 获取所有 public 方法(包括继承的)
        Method[] publicMethods = clazz.getMethods();

        // 获取所有方法(包括 private,不包括继承的)
        Method[] allMethods = clazz.getDeclaredMethods();

        // 获取指定方法(方法名 + 参数类型)
        Method addMethod = clazz.getDeclaredMethod("add", int.class, int.class);
        Method privateMethod = clazz.getDeclaredMethod("multiply", int.class, int.class);
    }
}

class Calculator {
    public int add(int a, int b) {
        return a + b;
    }

    private int multiply(int a, int b) {
        return a * b;
    }

    public static int divide(int a, int b) {
        return a / b;
    }

    public static void main(String[] args) {
        System.out.println("计算器");
    }
}

调用方法

java
public class MethodInvoke {

    public static void main(String[] args) throws Exception {
        Class<Calculator> clazz = Calculator.class;
        Calculator calculator = clazz.getDeclaredConstructor().newInstance();

        // 调用实例方法
        Method addMethod = clazz.getDeclaredMethod("add", int.class, int.class);
        Object result = addMethod.invoke(calculator, 10, 20);
        System.out.println("10 + 20 = " + result);

        // 调用私有方法
        Method multiplyMethod = clazz.getDeclaredMethod("multiply", int.class, int.class);
        multiplyMethod.setAccessible(true);
        result = multiplyMethod.invoke(calculator, 6, 7);
        System.out.println("6 * 7 = " + result);

        // 调用静态方法
        Method divideMethod = clazz.getDeclaredMethod("divide", int.class, int.class);
        result = divideMethod.invoke(null, 100, 5);  // 静态方法用 null
        System.out.println("100 / 5 = " + result);

        // 调用 main 方法
        Method mainMethod = clazz.getDeclaredMethod("main", String[].class);
        mainMethod.invoke(null, (Object) new String[]{});
    }
}

反射与泛型

Type 接口体系

┌─────────────────────────────────────────────────────────────────┐
│                         Type 接口体系                            │
├─────────────────────────────────────────────────────────────────┤
│                                                                  │
│                          Type                                    │
│                            │                                     │
│          ┌─────────────────┼─────────────────┐                   │
│          │                 │                 │                   │
│    Class              ParameterizedType  GenericArrayType         │
│   (普通类型)           (参数化类型)       (泛型数组)               │
│          │                 │                                   │
│          │     ┌───────────┴───────────┐                       │
│          │     │                       │                       │
│    TypeVariable               WildcardType                       │
│    (类型变量)                 (通配符类型)                        │
│                                                                  │
└─────────────────────────────────────────────────────────────────┘

获取泛型信息

java
public class GenericReflection {

    public static void main(String[] args) throws Exception {
        // 获取字段的泛型类型
        Field nameField = User.class.getDeclaredField("name");
        Type nameType = nameField.getGenericType();
        System.out.println("name 类型:" + nameType);  // class java.lang.String

        Field listField = User.class.getDeclaredField("tags");
        Type listType = listField.getGenericType();

        if (listType instanceof ParameterizedType) {
            ParameterizedType paramType = (ParameterizedType) listType;
            // 获取原始类型
            Type rawType = paramType.getRawType();
            System.out.println("原始类型:" + rawType);  // interface java.util.List

            // 获取泛型参数类型
            Type[] typeArgs = paramType.getActualTypeArguments();
            for (Type typeArg : typeArgs) {
                System.out.println("泛型参数:" + typeArg);  // class java.lang.String
            }
        }
    }
}

class User {
    private String name;
    private List<String> tags;
    private Map<String, Integer> scores;
}

反射与注解

读取注解信息

java
public class AnnotationReflection {

    public static void main(String[] args) throws Exception {
        // 检查类上的注解
        if (UserService.class.isAnnotationPresent(Table.class)) {
            Table table = UserService.class.getAnnotation(Table.class);
            System.out.println("表名:" + table.name());
        }

        // 检查字段上的注解
        for (Field field : UserService.class.getDeclaredFields()) {
            if (field.isAnnotationPresent(Column.class)) {
                Column column = field.getAnnotation(Column.class);
                System.out.println("列名:" + column.name() + ", 类型:" + column.type());
            }
        }

        // 检查方法上的注解
        for (Method method : UserService.class.getDeclaredMethods()) {
            if (method.isAnnotationPresent(Version.class)) {
                Version version = method.getAnnotation(Version.class);
                System.out.println("版本字段:" + version.field());
            }
        }
    }
}

// 注解定义
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@interface Table {
    String name();
}

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
@interface Column {
    String name();
    String type() default "VARCHAR";
}

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
@interface Version {
    String field() default "version";
}

// 使用注解
@Table(name = "t_user")
class UserService {
    @Column(name = "user_name", type = "VARCHAR(50)")
    private String username;

    @Column(name = "age")
    private int age;

    @Version
    public void update() { }
}

动态代理

JDK 动态代理

java
public class JdkProxyDemo {

    // 接口
    interface UserService {
        void addUser(String name);
        void deleteUser(Long id);
    }

    // 实现类
    static class UserServiceImpl implements UserService {
        @Override
        public void addUser(String name) {
            System.out.println("添加用户:" + name);
        }

        @Override
        public void deleteUser(Long id) {
            System.out.println("删除用户:" + id);
        }
    }

    // InvocationHandler 实现
    static class TimingHandler implements InvocationHandler {
        private Object target;

        public TimingHandler(Object target) {
            this.target = target;
        }

        @Override
        public Object invoke(Object proxy, Method method, Object[] args)
                throws Throwable {
            long start = System.currentTimeMillis();

            // 调用原始方法
            Object result = method.invoke(target, args);

            long end = System.currentTimeMillis();
            System.out.println(method.getName() + " 执行耗时:" + (end - start) + "ms");
            return result;
        }
    }

    public static void main(String[] args) {
        UserService target = new UserServiceImpl();

        // 创建代理对象
        UserService proxy = (UserService) Proxy.newProxyInstance(
            target.getClass().getClassLoader(),
            target.getClass().getInterfaces(),
            new TimingHandler(target)
        );

        // 使用代理
        proxy.addUser("张三");
        proxy.deleteUser(1L);
    }
}

CGLib 动态代理

java
public class CglibProxyDemo {

    static class UserService {
        public void addUser(String name) {
            System.out.println("添加用户:" + name);
        }
    }

    static class CglibProxy implements MethodInterceptor {

        public Object createProxy(Class<?> clazz) {
            Enhancer enhancer = new Enhancer();
            enhancer.setSuperclass(clazz);
            enhancer.setCallback(this);
            return enhancer.create();
        }

        @Override
        public Object intercept(Object obj, Method method, Object[] args,
                               MethodProxy proxy) throws Throwable {
            long start = System.currentTimeMillis();

            // 调用父类方法
            Object result = proxy.invokeSuper(obj, args);

            long end = System.currentTimeMillis();
            System.out.println(method.getName() + " 执行耗时:" + (end - start) + "ms");
            return result;
        }
    }

    public static void main(String[] args) {
        CglibProxy cglibProxy = new CglibProxy();
        UserService proxy = (UserService) cglibProxy.createProxy(UserService.class);

        proxy.addUser("张三");
    }
}

JDK 代理 vs CGLib 代理

特性JDK 动态代理CGLib 代理
实现方式实现接口继承父类
原理反射包 Proxy 类字节码生成
性能较快更快
限制必须有接口不能代理 final 类/final 方法
适用场景有接口的类无接口的类

反射的注意事项

性能开销

java
// 反射调用比直接调用慢很多
// 调用 1000 万次的耗时对比:

directCall();           // 10ms
method.invoke(obj);     // 500ms (慢 50 倍)

// 优化方法:
method.setAccessible(true);  // 跳过安全检查,提升性能

安全问题

java
// 反射可以访问 private 成员,破坏封装
Field field = clazz.getDeclaredField("password");
field.setAccessible(true);
field.set(user, "hacked");  // 危险操作!

// 在安全管理器下可能抛出异常
System.setSecurityManager(new SecurityManager());

最佳实践

┌─────────────────────────────────────────────────────────────────┐
│                       反射使用建议                               │
├─────────────────────────────────────────────────────────────────┤
│                                                                  │
│  1. 避免在高频调用场景使用反射                                    │
│  2. 反射访问 private 成员后,记得处理异常                          │
│  3. 使用 setAccessible(true) 提升反射性能                        │
│  4. 尽量使用 getDeclaredXXX 而非 getXXX(避免获取父类成员)        │
│  5. 缓存 Class 对象和 Method 对象,避免重复获取                   │
│                                                                  │
└─────────────────────────────────────────────────────────────────┘

总结

反射核心知识点

知识点面试频率实战重要性
Class 获取方式⭐⭐⭐⭐⭐⭐⭐⭐⭐
反射创建对象⭐⭐⭐⭐⭐⭐⭐⭐⭐
反射操作字段⭐⭐⭐⭐⭐⭐⭐⭐
反射调用方法⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐
泛型反射⭐⭐⭐⭐⭐⭐⭐
动态代理⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐
JDK vs CGLib⭐⭐⭐⭐⭐⭐⭐⭐

⚠️ 易错点提醒

  1. 反射访问 private 成员需要 setAccessible(true)
  2. 反射调用静态方法用 null 作为对象参数
  3. 反射调用可变参数方法需要手动处理
  4. 泛型擦除后,反射无法获取运行时泛型具体类型
  5. 动态代理的代理对象不能转型为具体类