实现步骤:
- 获取Person类的class文件对象
- 使用class文件对象中的方法getMethod / getMethds获取类中的成员方法Method
- 使用Method类中的方法invoke执行获取到的方法
现在拆分开详细描述:
第一步:获取类的class文件对象
详见:https://blog.csdn.net/qq_45083975/article/details/91959244
第二步:使用class文件对象中的方法getMethod / getMethds获取类中的成员方法Method
- Method[] getMethods() 获取类中所有的公共成员方法,包含继承的和实现的(一般不采用)
- Method[] getDeclaredMethods() 包括公共、保护、默认(包)访问和私有方法,但不包括继承的方法。
- Method getMethod(String name, Class<?>… parameterTypes) 获取指定公共成员方法。
- Method getDeclaredMethod(String name, Class<?>… parameterTypes) 获取指定已声明(公共、保护、默认(包)访问和私有)方法。
参数说明:
String name:获取的方法名字
比如:getName,setName,method 等
Class<?>… parameterTypes:成员方法参数列表的class文件对象
比如:int.class,double.class,String.class,Student.class 等
注意:
类中没有指定的方法,会抛出NoSuchMethodException 没有方法异常
注意:
在Method类中有一个方法
String getName() 以 String 形式返回此 Method 对象表示的方法名称。
第三步:使用Method类中的方法invoke执行获取到的方法
Object invoke(Object obj, Object… args)
对带有指定参数的指定对象调用由此 Method 对象表示的底层方法。
注意:
指定参数的指定对象这就用到了前面所说的快速创建对象的方法。使用newInstance()
参数说明:
Object obj:使用反射技术执行方法,需要对象的支持;执行哪个类中的方法,就传递哪个类的对象。这个对象可以使用反射快速创建对象的方式获取
Object… args:调用方法传递的实际参数
返回值:
方法的返回值
方法有返回值,获取的就是方法的返回值
方法没有返回值,返回值类型是void,值就是null(没有必要接收)
那么假如需要获取私有的构造方法:private void method()
私有方法没有权限运行,会抛出IllegalAccessException:非法访问异常
可以使用Method的父类AccessibleObject中的方法,取消权限检查
void setAccessible(boolean flag) 将此对象的 accessible 标志设置为指示的布尔值。
值为 true 则指示反射的对象在使用时应该取消 Java 语言访问检查。
值为 false 则指示反射的对象应该实施 Java 语言访问检查。
(上面的这种获取私有的构造方法的方式属于暴力反射,不推荐使用,因为它破坏了类的封装性)
下面我们举例说明:
package com.ccc.demo02Reflect;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
public class Demo04ReflectMethod {
public static void main(String[] args) throws Exception {
//1.获取Person类的class文件对象
Class clazz = Class.forName("com.ccc.demo03domain.Person");
//2.使用class文件对象中的方法getMethod/getMethds获取类中的成员方法Method
/*
Method[] getMethods() 获取类中所有的公共成员方法,包含继承的和实现的
Method[] getDeclaredMethods() 包括公共、保护、默认(包)访问和私有方法,
但不包括继承的方法。
*/
Method[] methods = clazz.getMethods();
for (Method m : methods) {
System.out.println(m);
}
System.out.println("======================");
Method[] declaredMethods = clazz.getDeclaredMethods();
for (Method method : declaredMethods) {
System.out.println(method);
}
System.out.println("======================");
/*
Method getMethod(String name, Class<?>... parameterTypes) 获取指定公共成员方法。
Method getDeclaredMethod(String name, Class<?>... parameterTypes)
获取指定已声明(公共、保护、默认(包)访问和私有)方法。
参数:
String name:获取的方法名字
比如:getName,setName,method
Class<?>... parameterTypes:成员方法参数列表的class文件对象
比如:int.class,double.class,String.class,Student.class 等
注意:
类中没有指定的方法,会抛出NoSuchMethodException 没有方法异常
*/
//获取 public String getName()
Method getNameMethod = clazz.getMethod("getName");
System.out.println(getNameMethod);
//输出:public java.lang.String com.ccc.demo03domain.Person.getName()
//获取 public void setName(String name)
Method setNameMethod = clazz.getMethod("setName", String.class);
System.out.println(setNameMethod);
//输出:public void com.ccc.demo03domain.Person.setName(java.lang.String)
//获取 private void method()
Method privateMethod = clazz.getDeclaredMethod("method");
System.out.println(privateMethod);
//输出:private void com.ccc.demo03domain.Person.method()
/*
注意:
在Method类中有一个方法
String getName() 以 String 形式返回此 Method 对象表示的方法名称。
*/
String name = setNameMethod.getName();
System.out.println(name); //输出:setName
System.out.println("---------------------------------------");
//3.使用Method类中的方法invoke执行获取到的方法
/*
Object invoke(Object obj, Object... args)
对带有指定参数的指定对象调用由此 Method 对象表示的底层方法。
参数:
Object obj:使用反射技术执行方法,需要对象的支持;执行哪个类中的方法,就传递哪个类的对象
这个对象可以使用反射快速创建对象的方式获取
Object... args:调用方法传递的实际参数
返回值:
方法的返回值
方法有返回值,获取的就是方法的返回值
方法没有返回值,返回值类型是void,值就是null(没有必要接收)
*/
Object obj = clazz.newInstance();
//public String getName()
Object v1 = getNameMethod.invoke(obj); //就相当于调用类中getName方法
System.out.println("v1:"+v1); //输出:v1:null 成员变量的默认值
//public void setName(String name)
Object v2 = setNameMethod.invoke(obj, "赵四"); //就相当于调用类中setName("赵四")方法
System.out.println("v2:"+v2); //输出:v2:null 方法没有返回值
v1 = getNameMethod.invoke(obj); //就相当于调用类中getName方法
System.out.println("v1:"+v1); //输出:v1:赵四
/*
private void method()
私有方法没有权限运行,会抛出IllegalAccessException:非法访问异常
可以使用Method的父类AccessibleObject中的方法,取消权限检查
void setAccessible(boolean flag) 将此对象的 accessible 标志设置为指示的布尔值。
值为 true 则指示反射的对象在使用时应该取消 Java 语言访问检查。
值为 false 则指示反射的对象应该实施 Java 语言访问检查。
*/
privateMethod.setAccessible(true); //取消权限检查-->暴力反射
privateMethod.invoke(obj);
}
}
Person类:
package com.ccc.demo03domain;
public class Person {
private String name;
private int age;
private String sex;
public Person() {
System.out.println("Person类的空参数构造方法");
}
public Person(String name, int age, String sex) {
this.name = name;
this.age = age;
this.sex = sex;
System.out.println("Person类的全参数构造方法");
}
private Person(String name, int age) {
this.name = name;
this.age = age;
System.out.println("Person类的私有构造方法");
}
//私有方法
private void method(){
System.out.println("Person类的私有方法");
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
", sex='" + sex + '\'' +
'}';
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
}