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