Java反射 #

一、反射概述 #

1.1 什么是反射 #

反射是Java在运行时获取类信息、创建对象、调用方法的机制。

1.2 反射的作用 #

  • 运行时获取类信息
  • 动态创建对象
  • 动态调用方法
  • 框架开发基础

二、Class类 #

2.1 获取Class对象 #

java
// 方式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");

// 方式4:类加载器
Class<?> clazz4 = ClassLoader.getSystemClassLoader().loadClass("java.lang.String");

2.2 Class常用方法 #

java
Class<?> clazz = String.class;

// 基本信息
clazz.getName();          // java.lang.String
clazz.getSimpleName();    // String
clazz.getPackage();       // package java.lang
clazz.getSuperclass();    // class java.lang.Object
clazz.getInterfaces();    // 实现的接口
clazz.getModifiers();     // 修饰符

// 判断
clazz.isInterface();      // 是否接口
clazz.isArray();          // 是否数组
clazz.isEnum();           // 是否枚举
clazz.isAnnotation();     // 是否注解

三、获取类成员 #

3.1 获取构造方法 #

java
Class<?> clazz = Person.class;

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

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

// 获取指定构造方法
Constructor<?> constructor = clazz.getConstructor(String.class, int.class);

// 获取私有构造方法
Constructor<?> privateConstructor = clazz.getDeclaredConstructor(String.class);
privateConstructor.setAccessible(true);  // 设置可访问

3.2 获取字段 #

java
Class<?> clazz = Person.class;

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

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

// 获取指定字段
Field nameField = clazz.getField("name");
Field privateField = clazz.getDeclaredField("age");
privateField.setAccessible(true);

3.3 获取方法 #

java
Class<?> clazz = Person.class;

// 获取所有public方法
Method[] methods = clazz.getMethods();

// 获取所有方法
Method[] allMethods = clazz.getDeclaredMethods();

// 获取指定方法
Method method = clazz.getMethod("setName", String.class);
Method privateMethod = clazz.getDeclaredMethod("privateMethod");
privateMethod.setAccessible(true);

四、创建对象 #

4.1 使用newInstance #

java
Class<?> clazz = Person.class;

// 无参构造
Person person = (Person) clazz.getDeclaredConstructor().newInstance();

// 有参构造
Constructor<?> constructor = clazz.getConstructor(String.class, int.class);
Person person2 = (Person) constructor.newInstance("张三", 25);

4.2 使用Constructor #

java
Class<?> clazz = Person.class;

Constructor<?> constructor = clazz.getDeclaredConstructor(String.class);
constructor.setAccessible(true);  // 私有构造
Person person = (Person) constructor.newInstance("张三");

五、操作字段 #

5.1 获取和设置字段值 #

java
public class Person {
    private String name;
    public int age;
}

Person person = new Person();
Class<?> clazz = person.getClass();

// 获取public字段
Field ageField = clazz.getField("age");
ageField.set(person, 25);
int age = (int) ageField.get(person);

// 获取private字段
Field nameField = clazz.getDeclaredField("name");
nameField.setAccessible(true);
nameField.set(person, "张三");
String name = (String) nameField.get(person);

5.2 字段类型 #

java
Field field = clazz.getDeclaredField("name");

Class<?> type = field.getType();
System.out.println(type.getName());  // java.lang.String

// 判断类型
if (field.getType() == String.class) {
    // 字符串类型
}

六、调用方法 #

6.1 基本调用 #

java
public class Person {
    public String getName() { return name; }
    public void setName(String name) { this.name = name; }
    private void privateMethod() { }
}

Person person = new Person();
Class<?> clazz = person.getClass();

// 调用public方法
Method setName = clazz.getMethod("setName", String.class);
setName.invoke(person, "张三");

Method getName = clazz.getMethod("getName");
String name = (String) getName.invoke(person);

// 调用private方法
Method privateMethod = clazz.getDeclaredMethod("privateMethod");
privateMethod.setAccessible(true);
privateMethod.invoke(person);

6.2 调用静态方法 #

java
public class Utils {
    public static int add(int a, int b) {
        return a + b;
    }
}

Method method = Utils.class.getMethod("add", int.class, int.class);
int result = (int) method.invoke(null, 10, 20);  // 静态方法,对象传null

6.3 调用main方法 #

java
Method main = clazz.getMethod("main", String[].class);
main.invoke(null, (Object) new String[]{"arg1", "arg2"});

七、反射应用 #

7.1 工厂模式 #

java
public class Factory {
    @SuppressWarnings("unchecked")
    public static <T> T create(String className) {
        try {
            Class<?> clazz = Class.forName(className);
            return (T) clazz.getDeclaredConstructor().newInstance();
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }
}

// 使用
Person person = Factory.create("com.example.Person");

7.2 属性复制 #

java
public static void copyProperties(Object source, Object target) {
    Class<?> sourceClass = source.getClass();
    Class<?> targetClass = target.getClass();
    
    for (Field sourceField : sourceClass.getDeclaredFields()) {
        try {
            Field targetField = targetClass.getDeclaredField(sourceField.getName());
            sourceField.setAccessible(true);
            targetField.setAccessible(true);
            targetField.set(target, sourceField.get(source));
        } catch (NoSuchFieldException e) {
            // 忽略不存在的字段
        }
    }
}

7.3 注解处理 #

java
public static void processAnnotations(Object obj) {
    Class<?> clazz = obj.getClass();
    
    for (Method method : clazz.getDeclaredMethods()) {
        if (method.isAnnotationPresent(Log.class)) {
            Log log = method.getAnnotation(Log.class);
            System.out.println("方法 " + method.getName() + " 有日志注解: " + log.value());
        }
    }
}

八、反射性能 #

8.1 性能问题 #

反射比直接调用慢,因为:

  • 需要查找方法
  • 需要进行安全检查
  • 需要进行类型转换

8.2 优化建议 #

java
// 缓存Method对象
private static final Map<String, Method> METHOD_CACHE = new ConcurrentHashMap<>();

public static Method getMethod(Class<?> clazz, String name, Class<?>... paramTypes) {
    String key = clazz.getName() + "." + name;
    return METHOD_CACHE.computeIfAbsent(key, k -> {
        try {
            return clazz.getMethod(name, paramTypes);
        } catch (NoSuchMethodException e) {
            throw new RuntimeException(e);
        }
    });
}

// 使用setAccessible提高性能
method.setAccessible(true);

九、总结 #

说明
Class 类信息
Constructor 构造方法
Field 字段
Method 方法

反射要点:

  • 反射可以突破封装
  • setAccessible可以访问私有成员
  • 注意性能问题
  • 合理使用缓存
最后更新:2026-03-26