java反射
JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取类信息以及动态调用对象的方法的功能称为java语言的反射机制。
Java反射机制主要提供了以下功能:
- 在运行时构造任意一个类的对象
- 在运行时获取任意一个类所具有的成员变量和方法
- 在运行时调用任意一个对象的方法(属性)
- 生成动态代理
Class 是一个类; 一个描述类的类.
封装了描述方法的 Method,

package reflect; public class Person { String name; private int age; private Integer sal; public String getName() { return name; } public void setName(String name) { this.name = name; System.out.println("执行了setName()方法"); } public int getAge() { return age; } public void setAge(int age) { this.age = age; System.out.println("执行了setAge()方法"); } public Integer getSal() { return sal; } public void setSal(Integer sal) { this.sal = sal; System.out.println("执行了setAge()方法"); } public Person(String name, int age, Integer sal) { super(); this.name = name; this.age = age; this.sal = sal; } public Person() { super(); } private void Say(){ System.out.println("我好痛苦,我觉得生不如死!"); } public void test(String name,Integer sal){ System.out.println("调用成功"); } }

package reflect; public class Student extends Person{ private Double score; public Double getScore() { return score; } public void setScore(Double score) { this.score = score; } private void Study(){ System.out.println("我太累了,不想学习"); } }
1、如何描述方法-Method(getDeclaredMethod()不能获取父类方法 getMethod() 一般只能获取私有方法)
@Test public void testMethod() throws ClassNotFoundException, NoSuchMethodException, SecurityException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException{ Class clazz=Class.forName("reflect.Person"); //1、获取clazz对应类中的所有方法--方法数组1 Method[] methods=clazz.getMethods(); for(Method method:methods){ System.out.println(method.getName()); } System.out.println("-----------------------------------------------------"); //2、获取所有方法包括私有方法---方法数组2 methods=clazz.getDeclaredMethods(); for(Method method:methods){ System.out.println(method.getName()); } //3.1、获取指定的方法 //需要参数名称和参数列表,无参则不需要 //对于方法 public void setName(String name){} Method method=clazz.getDeclaredMethod("setName",String.class); System.out.println(method); //而对于方法public void setAge(int age){} method=clazz.getDeclaredMethod("setAge",int.class); System.out.println(method); method=clazz.getDeclaredMethod("setSal",Integer.class ); System.out.println(method); //4、执行方法 invoke() 第一个参数表示执行哪个对象的方法,剩下的参数是执行方法时需要转入的参数 Object obj=clazz.newInstance(); method.invoke(obj, 2000); //如果一个方法是私有方法,3.1是可以获取到的,但是这一步却不能执行 //私有方法的执行,必须在调用invoke之前加上一句method.setAccessible(true) method=clazz.getDeclaredMethod("Say",null); method.setAccessible(true); method.invoke(obj, null); }
主要用到的两个方法
/** * @param name the name of the method * @param parameterTypes the list of parameters * @return the {@code Method} object that matches the specified */ public Method getMethod(String name, Class<?>... parameterTypes){ } /** * @param obj the object the underlying method is invoked from * @param args the arguments used for the method call * @return the result of dispatching the method represented by */ public Object invoke(Object obj, Object... args){ }
自定义工具方法
自定义一个方法
把类对象和类方法名作为参数,执行方法
把全类名和方法名作为参数,执行方法
假设:Person类里面有一个方法
public void test(String name,Integer sal){ System.out.println("调用成功"); }
1. 把类对象和类方法名作为参数,执行方法(下面的方法没有考虑到无参的方法)
/** * @param obj: 方法执行的那个对象. * @param methodName: 类的一个方法的方法名. 该方法也可能是私有方法. * @param args: 调用该方法需要传入的参数 * @return: 调用方法后的返回值 * 把类对象和类方法名作为参数,执行方法 */ public Object invoke(Object obj,String methodName,Object ... args) throws Exception{ //1、获取Method对象 //因为getMethod的参数为Class类型,所以要把参数args转换为对应的Class类型 Class[] parameterTypes=new Class[args.length]; for(int i=0;i<args.length;i++){ parameterTypes[i]=args[i].getClass(); System.out.println(parameterTypes[i]); } Method method=obj.getClass().getDeclaredMethod(methodName, parameterTypes); //如果使用getDeclaredMethod(),就不能获取父类方法,如果使用getMethod()就不能获取私有方法 //2、执行Method方法 //返回方法返回值 return method.invoke(obj, args); }
@Test public void testInvoke() throws Exception{ Object obj=new Person(); invoke(obj,"test","李刚",20000); }
2.把全类名和方法名作为参数,执行方法(没有考考虑无参的方法)
public Object invoke(String className,String methodName,Object...args){ Object obj=null; try{ obj=Class.forName(className).newInstance(); return invoke(obj,methodName,args); }catch(Exception e){ e.printStackTrace(); } return null; }
这种反射实现的主要功能是可配置和低耦合。只需要类名和方法名,而不需要一个类对象就可以执行一个方法。如果我们把全类名和方法名放在一个配置文件中,就可以根据调用配置文件来执行方法
如何获取父类定义的(私有)方法
前面说一般使用getDeclaredMethod获取方法(因为此方法可以获取类的私有方法,但是不能获取父类方法)
如何获取父类方法呢,getMethod
首先我们要知道,如何获取类的父亲:
比如有一个类,继承自Person
@Test public void testGetSuperClass() throws Exception{ String className="reflect.Student"; Class clazz=Class.forName(className); Class superClazz=clazz.getSuperclass(); System.out.println(superClazz);//class reflect.Person }
此时如果Student中有一个方法是私有方法method1(int age); Person中有一个私有方法method2();
怎么调用 定义一个方法,不但能访问当前类的私有方法,还要能父类的私有方法
/** * * @param obj: 某个类的一个对象 * @param methodName: 类的一个方法的方法名. * 该方法也可能是私有方法, 还可能是该方法在父类中定义的(私有)方法 * @param args: 调用该方法需要传入的参数 * @return: 调用方法后的返回值*/ public Object invoke2(Object obj,String methodName,Object... args){ Class[] parameterTypes=new Class[args.length]; for(int i = 0; i < args.length; i++){ parameterTypes[i] = args[i].getClass(); } try{ Method method=getMethod(obj.getClass(),methodName,parameterTypes); method.setAccessible(true); return method.invoke(obj, args); }catch(Exception e){ e.printStackTrace(); } return null; } /** * 获取 clazz 的 methodName 方法. 该方法可能是私有方法, 还可能在父类中(私有方法) * 如果在该类中找不到此方法,就向他的父类找,一直到Object类为止 * 这个方法的另一个作用是根据一个类名,一个方法名,追踪到并获得此方法*/ public Method getMethod(Class clazz,String methodName,Class ...parameterTypes){ for(;clazz!=Object.class;clazz=clazz.getSuperclass()){ try{ Method method=clazz.getDeclaredMethod(methodName, parameterTypes); return method; }catch(Exception e){ } } return null; }
3.2 如何描述字段-Field
@Test public void testField() throws ClassNotFoundException, NoSuchFieldException, SecurityException, IllegalArgumentException, IllegalAccessException{ String className="reflect.Person"; Class clazz=Class.forName(className); //1、获取字段 //获取所有字段,字段数组 //可以获取公用和私有的所有字段,但不能获取父类字段 Field[] fields=clazz.getDeclaredFields(); for(Field field:fields){ System.out.println(field); } Person person=new Person(); person.setName("郭维平"); person.setSal(6000); //1.2获取指定字段 Field field=clazz.getDeclaredField("name"); System.out.println("-----字段名称-------"+field.getName()); //2、使用字段 //2.1获取指定对象的指定字段的值 Object val=field.get(person); System.out.println(val); field.set(person, "周益涛"); System.out.println(person.getName()); field=clazz.getDeclaredField("age"); field.setAccessible(true);//如果字段是私有的,不管是读值还是写值,都必须先调用setAccessible(true);比如Person类中,字段name字段是公用的,age是私有的 System.out.println("--------age---------"+field.get(person)); }
输出结果:
java.lang.String com.idea.test.Person.name private int com.idea.test.Person.age private java.lang.Integer com.idea.test.Person.sal 执行了setName()方法 执行了setAge()方法 -----字段名称-------name 郭维平 周益涛 --------age---------0
但是如果需要访问父类中的(私有)字段:(好像有点问题需注意)
@Test public void testField() throws ClassNotFoundException, NoSuchFieldException, SecurityException, IllegalArgumentException, IllegalAccessException, InstantiationException{ //创建className对应类的对象,并为其fieldName赋值val //Student继承自Person,age是Person类的私有字段 String className="reflect.Student"; String fieldName="age"; Object val=26; Object obj=null; //1、创建className对应类的对象 Class clazz=Class.forName(className); //2、创建fieldName对象字段的对象 Field field=getField(clazz,fieldName); //3、为此对象赋值 obj=clazz.newInstance(); setFieldValue(obj,field,val); //4、获取此对象的值 Object value=getFieldValue(obj,field); } public Object getFieldValue(Object obj,Field field) throws IllegalArgumentException, IllegalAccessException{ field.setAccessible(true); return field.get(obj); } public void setFieldValue(Object obj,Field field,Object val) throws IllegalArgumentException, IllegalAccessException{ field.setAccessible(true); field.set(obj, val); } public Field getField(Class clazz,String fieldName) throws NoSuchFieldException, SecurityException{ Field field= null; for(Class clazz2=clazz;clazz2!=Object.class;clazz2=clazz2.getSuperclass()){ field=clazz2.getDeclaredField(fieldName); } return field; }
3.3如何描述构造器-Constructor
@Test
public void testConstructor() throws ClassNotFoundException, NoSuchMethodException, SecurityException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException{
String className="reflect.Person";
Class<Person> clazz=(Class<Person>)Class.forName(className);
//1、获取Constructor对象
//1.1获取全部
Constructor<Person>[] constructors=(Constructor<Person>[])clazz.getConstructors();
for(Constructor constructor:constructors){
System.out.println(constructor);
}
// // 1.2获取某一个,需要参数列表
Constructor<Person> constructor=clazz.getConstructor(String.class,int.class,Integer.class);
Object obj=constructor.newInstance("周益涛",18,10000);
System.out.println("-----"+obj.toString());
}
3.4 如何描述注解 -- Annotation

package reflect; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; @Retention(RetentionPolicy.RUNTIME) @Target(value={ElementType.METHOD}) public @interface AgeValidator { public int min(); public int max(); }
此注解只能用在方法上
@AgeValidator(min=12,max=30) public void setAge(int age) { this.age = age; System.out.println("执行了setAge()方法"); }
那么我们在给Person类对象的age赋值时,是感觉不到注解的存在的
@Test public void testAnnotation(){ Person p=new Person(); p.setAge(15); }
必须通过反射的方式为属性赋值,才能获取到注解
@Test public void testAnnotation1() throws InstantiationException, IllegalAccessException, ClassNotFoundException, NoSuchMethodException, SecurityException{ String className="reflect.Person"; Class clazz=Class.forName(className); Object obj=clazz.newInstance(); Method method=clazz.getDeclaredMethod("setAge",int.class); int val=6; //获取指定名称的注解 Annotation annotation=method.getAnnotation(AgeValidator.class); if(annotation!=null){ if(annotation instanceof AgeValidator){ AgeValidator ageValidator=(AgeValidator)annotation; if(val<ageValidator.min() ||val>ageValidator.max()){ throw new RuntimeException("年龄非法"); } } } }
反射小结
1. Class: 是一个类; 一个描述类的类.
封装了描述方法的 Method,
描述字段的 Filed,
描述构造器的 Constructor 等属性.
2. 如何得到 Class 对象:
2.1 Person.class
2.2 person.getClass()
2.3 Class.forName("com.atguigu.javase.Person")
3. 关于 Method:
3.1 如何获取 Method:
1). getDeclaredMethods: 得到 Method 的数组.
2). getDeclaredMethod(String methondName, Class ... parameterTypes)
3.2 如何调用 Method
1). 如果方法时 private 修饰的, 需要先调用 Method 的 setAccessible(true), 使其变为可访问
2). method.invoke(obj, Object ... args);
4. 关于 Field:
4.1 如何获取 Field: getField(String fieldName)
4.2 如何获取 Field 的值:
1). setAccessible(true)
2). field.get(Object obj)
4.3 如何设置 Field 的值:
field.set(Obejct obj, Object val)
5. 了解 Constructor 和 Annotation
6. 反射和泛型.
6.1 getGenericSuperClass: 获取带泛型参数的父类, 返回值为: BaseDao<Employee, String>
6.2 Type 的子接口: ParameterizedType
6.3 可以调用 ParameterizedType 的 Type[] getActualTypeArguments() 获取泛型参数的数组

【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!