Appearance
反射
反射简介
什么是反射?
反射(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 | ⭐⭐⭐⭐ | ⭐⭐⭐⭐ |
⚠️ 易错点提醒:
- 反射访问 private 成员需要
setAccessible(true) - 反射调用静态方法用
null作为对象参数 - 反射调用可变参数方法需要手动处理
- 泛型擦除后,反射无法获取运行时泛型具体类型
- 动态代理的代理对象不能转型为具体类