java反射
字数 3572 2025-08-24 07:48:22
Java反射机制详解
一、反射概念
Java反射是指在程序运行期间对于类的属性、方法、构造方法等进行动态访问和操作的机制。通过Java反射API,程序能够在运行期获取类的信息,操作类的属性、方法、构造方法,创建类的对象等。
核心特点:不适用new创建对象而访问类中方法的过程即可成为反射。
二、反射相关包
Java反射的相关类位于 java.lang.reflect.* 包中。
三、反射的作用
- 获取任意类的名称、package信息、所有属性、方法、注解、类型、类加载器等
- 获取任意对象的属性,并且能改变对象的属性
- 调用任意对象的方法
- 判断任意一个对象所属的类
- 实例化任意一个类的对象
- 实现动态装配,降低代码的耦合度,动态代理等
四、核心反射类
java.lang.Class:代表整个字节码,代表一个类型,代表整个类java.lang.reflect.Method:代表字节码中的方法字节码,代表类中的方法java.lang.reflect.Constructor:代表字节码中的构造方法字节码,代表类中的构造方法java.lang.reflect.Field:代表字节码中的属性字节码,代表类中的成员变量(静态变量+实例变量)
注意:必须先获取Class才能获取Method、Constructor、Field。
五、获取Class实例的三种方法
-
Class.forName("完整类名带包名")Class<?> cls = Class.forName("java.util.ArrayList"); -
对象.getClass()Object obj = new String("Hello World"); Class<? extends Object> objClass = obj.getClass(); -
类名.classClass<String> strClass = String.class;
六、Class类常用方法
| 方法 | 描述 |
|---|---|
getFields() |
获得类的public类型的属性 |
getDeclaredFields() |
获得类的所有属性 |
getField(String name) |
获得类的指定属性 |
getMethods() |
获得类的public类型的方法 |
getMethod(String name, Class[] args) |
获得类的指定方法 |
getConstrutors() |
获得类的public类型的构造方法 |
getConstrutor(Class[] args) |
获得类的特定构造方法 |
newInstance() |
通过类的无参构造方法创建对象 |
getName() |
获得类的完整名字 |
getPackage() |
获取此类所属的包 |
getSuperclass() |
获得此类的父类对应的Class对象 |
七、通过反射实例化对象
-
基本方法:
对象.newInstance()注意:没有公共的无参构造函数,newInstance()方法就会抛出InstantiationException异常
-
使用特定构造函数:
Class<MyClass> cls = MyClass.class; Constructor<MyClass> constructor = cls.getDeclaredConstructor(int.class, String.class); MyClass myObj = constructor.newInstance(42, "Hello");
八、Class.forName导致类加载
如果只是希望一个类的静态代码块执行,其它代码一律不执行,可以使用:
Class.forName("完整类名");
这个方法的执行会导致类加载,类加载时,静态代码块执行。
九、反射Field(反射/反编译一个类的属性)
Class类相关方法:
public T newInstance():创建对象public String getName():返回完整类名带包名public String getSimpleName():返回类名public Field[] getFields():返回类中public修饰的属性public Field[] getDeclaredFields():返回类中所有的属性public Field getDeclaredField(String name):根据属性名name获取指定的属性public native int getModifiers():获取属性的修饰符列表,返回的修饰符是一个数字public Method[] getDeclaredMethods():返回类中所有的实例方法public Method getDeclaredMethod(String name, Class<?>... parameterTypes):根据方法名name和方法形参获取指定方法public Constructor<?>[] getDeclaredConstructors():返回类中所有的构造方法public Constructor getDeclaredConstructor(Class<?>... parameterTypes):根据方法形参获取指定的构造方法public native Class<? super T> getSuperclass():返回调用类的父类public Class<?>[] getInterfaces():返回调用类实现的接口集合
Field类方法:
public String getName():返回属性名public int getModifiers():获取属性的修饰符列表public Class<?> getType():以Class类型,返回属性类型public void set(Object obj, Object value):设置属性值public Object get(Object obj):读取属性值
给属性赋值和读取:
-
直接赋值:
对象.属性 = 值; 对象.属性; -
通过反射赋值:
属性.set(对象, 值); 属性.get(对象);
示例代码:
class ReflectTest07 {
public static void main(String[] args) throws Exception {
// 不使用反射机制给属性赋值
Student student = new Student();
student.no = 1111;
System.out.println(student.no);
// 使用反射机制给属性赋值
Class studentClass = Class.forName("javase.reflectBean.Student");
Object obj = studentClass.newInstance();
Field noField = studentClass.getDeclaredField("no");
noField.set(obj, 22222);
System.out.println(noField.get(obj));
}
}
十、反射Method(反射/反编译一个类的方法)
Method类方法:
public String getName():返回方法名public int getModifiers():获取方法的修饰符列表public Class<?> getReturnType():以Class类型,返回方法类型public Class<?>[] getParameterTypes():返回方法的修饰符列表public Object invoke(Object obj, Object... args):调用方法
调用方法:
方法.invoke(对象, 实参);
示例代码:
class ReflectTest10 {
public static void main(String[] args) throws Exception {
// 不使用反射机制调用方法
UserService userService = new UserService();
System.out.println(userService.login("admin", "123") ? "登入成功!" : "登入失败!");
// 使用反射机制调用方法
Class userServiceClass = Class.forName("javase.reflectBean.UserService");
Object obj = userServiceClass.newInstance();
Method loginMethod = userServiceClass.getDeclaredMethod("login", String.class, String.class);
Object resValues = loginMethod.invoke(obj, "admin", "123");
System.out.println(resValues);
}
}
十一、反射Constructor(反射/反编译一个类的构造方法)
Constructor类方法:
public String getName():返回构造方法名public int getModifiers():获取构造方法的修饰符列表public Class<?>[] getParameterTypes():返回构造方法的修饰符列表public T newInstance(Object ... initargs):创建对象
示例代码:
class ReflectTest12 {
public static void main(String[] args) throws Exception {
// 不使用反射创建对象
Vip vip1 = new Vip();
Vip vip2 = new Vip(123, "zhangsan", "2001-10-19", false);
// 使用反射机制创建对象
Class vipClass = Class.forName("javase.reflectBean.Vip");
// 调用无参数构造方法
Object obj1 = vipClass.newInstance();
System.out.println(obj1);
// 调用有参数的构造方法
Constructor c1 = vipClass.getDeclaredConstructor(int.class, String.class, String.class, boolean.class);
Object obj2 = c1.newInstance(321, "lsi", "1999-10-11", true);
System.out.println(obj2);
// 获取无参数构造方法
Constructor c2 = vipClass.getDeclaredConstructor();
Object obj3 = c2.newInstance();
System.out.println(obj3);
}
}
十二、获取父类和实现的接口
Class类方法:
public native Class<? super T> getSuperclass():返回调用类的父类public Class<?>[] getInterfaces():返回调用类实现的接口集合
示例代码:
class ReflectTest13 {
public static void main(String[] args) throws Exception {
Class vipClass = Class.forName("java.lang.String");
Class superclass = vipClass.getSuperclass();
Class[] interfaces = vipClass.getInterfaces();
System.out.println(superclass.getName());
for (Class i : interfaces) {
System.out.println(i.getName());
}
}
}
十三、关键点总结
- Class.forName(classname):获取classname类中的所有属性包括类名
- Class.newInstance():实例化对象,并触发该类的构造方法
- Class.getMethod(method name,arg):获取一个对象中的public方法
- Method.invoke():执行方法
- 普通方法:第一个参数为该方法所在的对象
- 静态方法:第一个参数是null或者该方法所在的类
- 第二个参数为要执行方法的参数
- obj.getClass():通过对象实例获取它的类
- Y1.class:直接通过类名获取Class对象
十四、形参和实参
- 形参:定义函数时使用的参数,用于接收调用该函数时传入的参数
- 实参:调用函数时,函数名后面括号中的参数
十五、变量赋值方式
- 基本数据类型:赋值的是变量所保存的数据值
- 引用数据类型:赋值的是变量所保存的数据的地址值
十六、值传递机制
- 基本数据类型参数:实参赋给形参的是实参真实存储的数据值
- 引用数据类型参数:实参赋给形参的是实参存储数据的地址值
示例说明:
public class ValueTransferTest1 {
public static void main(String[] args) {
int m = 10;
int n = 20;
swap(m, n); // 交换失败,因为是值传递
System.out.println("m = " + m + ", n = " + n);
}
public static void swap(int m, int n) {
int temp = m;
m = n;
n = temp;
}
}
public class ValueTransferTest2 {
public static void main(String[] args) {
Data data = new Data();
data.m = 10;
data.n = 20;
swap(data); // 交换成功,因为是引用传递
System.out.println("m = " + data.m + ", n = " + data.n);
}
public static void swap(Data data) {
int temp = data.m;
data.m = data.n;
data.n = temp;
}
}
class Data {
int m;
int n;
}
十七、反射应用场景
- 动态代理:AOP实现
- 框架设计:Spring等框架的核心
- 注解处理:运行时注解处理器
- 工具类:通用工具方法
- 测试工具:Mock测试等
十八、反射性能考虑
反射操作比直接调用慢,因为:
- 需要动态解析类型
- 需要安全检查
- 编译器无法优化
优化建议:
- 缓存Class对象
- 缓存Method/Field/Constructor对象
- 减少安全检查(setAccessible(true))