java中反射的基本使用
约 1749 字大约 6 分钟
2025-07-11
前言
- 反射是 java 的一个特性,是 java 提供的一种机制。
- 反射允许程序在运行时查询和操作类的信息。
- 反射对很多高级功能(框架设计、动态代理等)都很有用。
- 反射提供了很多类和接口来操作 class 对象,如 java.lang.Class java.lang.reflect.Constructor java.lang.reflect.Method java.lang.reflect.Field
- 反射就是在运行时才知道要操作的类是什么,并且可以在运行时获取类的完整构造,并调用对应的方法。
理论基础
1. 获取 Class 对象
// 方式 1: 使用类的.class 属性
Class<?> clazz = MyClass.class;
// 方式 2: 使用 Class.forName()
Class<?> clazz2 = Class.forName("com.example.MyClass"); //这个字符串可能是一个参数,也就是“在运行时才知道要操作的类是什么”// 方式3: 使用对象的getClass()方法 MyClass myClass = new MyClass(); Class<?> clazz3 = myClass.getClass();
注意
先获取反射对象 clazz,后续所有的操作都是用 clazz 来执行的,包括建立对象、获取类的构造器、方法、属性。
2. 获取类的构造函数
// 获取所有构造函数
Constructor<?>[] constructors = clazz.getConstructors();
// 获取指定的构造函数
Constructor<?> constructor = clazz.getConstructor(String.class, int.class);
Object obj = constructor.newInstance("John", 30);
3. 创建对象
// 通过无参构造方法创建实例
Constructor<?> constructor = clazz.getConstructor();
Object obj = constructor.newInstance();
// 带参构造函数创建实例 (括号里的两个类型就是下面 newInstance() 里的两个参数类型)
Constructor<?> constructor = clazz.getConstructor(String.class, int.class);
Object obj = constructor.newInstance("Alice", 30);
4. 获取类的方法
// 获取所有公共方法
Method method = clazz.getMethod("methodName", String.class); // 指定方法名和参数类型
method.invoke(obj, "parameter");
// 获取私有方法
Method privateMethod = clazz.getDeclaredMethod("privateMethod");
privateMethod.setAccessible(true); // 允许访问私有方法
privateMethod.invoke(obj);
5. 获取类的字段
// 获取字段
Field field = clazz.getField("fieldName"); // 获取公共字段
Object fieldValue = field.get(obj); // 获取字段的值
// 访问私有字段
Field privateField = clazz.getDeclaredField("privateField");
privateField.setAccessible(true); // 允许访问私有字段
Object value = privatePrice.get(obj);//获取私有字段的值
privateField.set(obj, "newValue"); // 修改字段的值
代码实践
目录结构
Apple.java
package com.example.reflect;
public class Apple {
public String color;
private int price;
public Apple() {
}
public Apple(String color, int price) {
this.color = color;
this.price = price;
}
public void setColor(String color) {
this.color = color;
}
public void setPrice(int price) {
this.price = price;
}
public String getColor() {
return color;
}
public int getPrice() {
return price;
}
}
正常调用(不用反射)
Apple apple = new Apple();
apple.setColor("red");
apple.setPrice(5);
System.out.println("---------------- 正常调用 ----------------");
System.out.println("[public] color: " + apple.color);
System.out.println("[public] getColor(): " + apple.getColor());
System.out.println("[private] price: "+apple.getPrice());
运行结果:
用反射调用(异常先都直接抛出):
获取 class 对象:
// 1. 获取class对象 Class<Apple> clazz = Apple.class; Class<?> clz = Class.forName("com.example.reflect.Apple"); System.out.println(clazz); System.out.println(clz);
运行结果:证明两种方法获取的 Class 类是一样的(没有测试第三种方法)。
获取反射对象 clazz 后,后续所有的操作都是用 clazz 来执行的,包括建立对象、获取类/对象的构造器、方法、属性。
用 clazz 获取类的构造器:只是用 clazz 来获取,不用 clz(为了简化代码)
// 2. 获取构造器 // 2.1 获取空构造器 Constructor<Apple> constructor = clazz.getConstructor(); Apple apple = constructor.newInstance();//创建对象 System.out.println(apple); // 2.2 获取有参构造器 Constructor<Apple> constructor1 = clazz.getConstructor(String.class,int.class ); Apple apple1 = constructor1.newInstance("Green", 2);//创建对象 System.out.println(apple1);
运行结果:可见获取空构造器和有参构造器都成功了。
用 clazz 创建对象:
在上一步获取构造器中,
constructor.newInstance()
和constructor1.newInstance("Green", 2);
就是创建了对象。用 clazz 获取类的方法:以用有参构造器创建对象为例(为了简化代码)
// 4. 获取类的方法 // 4.1 获取有参方法(第一个参数是方法名,第二个参数是setColor(String color) 的类型) Method setColorMethod = clazz.getMethod("setColor", String.class); Method setPriceMethod = clazz.getMethod("setPrice", int.class); // // 4.2 获取无参方法 Method getColorMethod = clazz.getMethod("getColor"); Method getPriceMethod = clazz.getMethod("getPrice"); // 4.1.1 调用有参方法, // .invoke() 就是调用这个方法,第一个参数是要操作的对象,第二个参数是修改的参数值 setColorMethod.invoke(apple, "Yellow"); setPriceMethod.invoke(apple,66); // 4.2.1 调用无参方法 // .invoke() 就是调用这个方法,参数是要操作的对象 Object color = getColorMethod.invoke(apple); Object price = getPriceMethod.invoke(apple); System.out.println("color: "+ color); System.out.println("price: "+ price);
运行结果:apple 从
constructor.newInstance("Green", 2);
变成了Yellow,66
用 clazz 获取类的字段:上一步是用 getPrice() 获取 price,这一步是直接访问 price
Apple.java
中public String color; private int price;
分别获取一下:// 5. 获取类的字段 // 5.1 获取字段 Field field = clazz.getField("color");//获取公共字段 Object color = field.get(apple);//获取 apple对象中 字段color的值 System.out.println(color); // 5.2 获取私有字段 Field privateField = clazz.getDeclaredField("price");//注意这里方法变成了 getDeclaredField() privateField.setAccessible(true);//允许访问私有字段,不设置这一句运行会报错 Object price = privateField.get(apple);//获取私有字段的值 System.out.println(price);
运行结果:
Main.java 全部代码
package com.example;
import com.example.reflect.Apple;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
public class Main {
/**
* 【正射】未运行时就已经确定了要运行的类
* 【反射】就是在运行时才知道要操作的类是什么,并且可以在运行时获取类的完整构造,并调用对应的方法。
*
* 反射是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法,对于任意一个对象,都能够调用它的任意方法和属性
*/
public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException, NoSuchFieldException {
// 正常调用
// Apple apple = new Apple();
// apple.setColor("red");
// apple.setPrice(5);
// System.out.println("---------------- 正常调用 ----------------");
// System.out.println("[public] color: " + apple.color);
// System.out.println("[public] getColor(): " + apple.getColor());
// System.out.println("[private] price: "+apple.getPrice());
System.out.println("**********************************");
// 1. 获取class对象
Class<Apple> clazz = Apple.class;
// 2. 获取构造器
Constructor<Apple> constructor = clazz.getConstructor(String.class, int.class);
// 3. 创建对象
Apple apple = constructor.newInstance("Green", 2);
// // 4. 获取类的方法
// // 4.1 获取有参方法(第一个参数是方法名,第二个参数是setColor(String color) 的类型)
// Method setColorMethod = clazz.getMethod("setColor", String.class);
// Method setPriceMethod = clazz.getMethod("setPrice", int.class);
// // // 4.2 获取无参方法
// Method getColorMethod = clazz.getMethod("getColor");
// Method getPriceMethod = clazz.getMethod("getPrice");
// // 4.1.1 调用有参方法,
// // .invoke() 就是调用这个方法,第一个参数是要操作的对象,第二个参数是修改的参数值
// setColorMethod.invoke(apple, "Yellow");
// setPriceMethod.invoke(apple,66);
// // 4.2.1 调用无参方法
// // .invoke() 就是调用这个方法,参数是要操作的对象
// Object color = getColorMethod.invoke(apple);
// Object price = getPriceMethod.invoke(apple);
// System.out.println("color: "+ color);
// System.out.println("price: "+ price);
// 5. 获取类的字段
// 5.1 获取字段
Field field = clazz.getField("color");//获取公共字段
Object color = field.get(apple);//获取 apple对象中 字段color的值
System.out.println(color);
// 5.2 获取私有字段
Field privateField = clazz.getDeclaredField("price");//注意这里方法变成了 getDeclaredField()
privateField.setAccessible(true);//允许访问私有字段,不设置这一句运行会报错
Object price = privateField.get(apple);//获取私有字段的值
System.out.println(price);
}
}
参考文档
- 大白话说 Java 反射:入门、使用、原理
- chat gpt 问答