一.获取类的成员变量
package com.njau.d2_reflect;public class Cat {public static int a;public static final String COUNTRY = "中国";private String name;private int age;public Cat(String name, int age) {System.out.println("有参数构造器执行了!");this.name = name;this.age = age;}public Cat() {System.out.println("无参构造器执行了!");}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;}@Overridepublic String toString() {return "Cat{" +"name='" + name + '\'' +", age=" + age +'}';}
}

* public Field[] getFields() 获取类的全部成员变量(只能获取public修饰的)
* public Field[] getDeclaredFields() 获取类的全部成员变量(只要存在就能拿到)
* public Field getField() 获取类的某个成员变量(只能获取public修饰的)
* public Field getDeclaredField() 获取类的全部成员变量(只要存在就能拿到)
返回回来的是一个Filed类型的对象。可以使用数组接收多个。
package com.njau.d2_reflect;import org.junit.Test;import java.lang.reflect.Field;/*** 目标:掌握获取类的成员变量* Class提供了从类中获取成员变量的方法* public Field[] getFields() 获取类的全部成员变量(只能获取public修饰的)* public Field[] getDeclaredFields() 获取类的全部成员变量(只要存在就能拿到)* public Field getField(String name) 获取类的某个成员变量(只能获取public修饰的)* public Field getDeclaredField(String name) 获取类的全部成员变量(只要存在就能拿到)* 获取到成员变量的作用:依然是赋值,取值* void set(Object obj,Object value) 赋值* Object get(Object obj) 取值* public void setAccessible(boolean flag) 设置为true,表示禁止检查访问控制(暴力反射)*/public class Test3Field {@Testpublic void testGetFields() throws Exception {// 1、反射第一步:首先获取到类Class对象Class c = Cat.class;// 2、public Field[] getFields() 获取类的全部成员变量(只能获取public修饰的)
// Field[] fields = c.getFields();Field[] fields = c.getDeclaredFields(); // 获取类的全部成员变量(只要存在就能拿到)for (Field field : fields) {System.out.println(field.getName() + "--->" + field.getType());}// 3、public Field getField(String name) 获取类的某个成员变量(只能获取public修饰的)Field fName = c.getDeclaredField("name");System.out.println(fName.getName() + "--->" + fName.getType()); // name--->class java.lang.String// 4、public Field getDeclaredField(String name) 获取类的某个成员变量(只要存在就能拿到)Field fAge = c.getDeclaredField("age");System.out.println(fAge.getName() + "--->" + fAge.getType()); // age--->int}
}

获取成员变量的作用:依然是赋值、取值
使用set进行赋值,但是赋值时必须要创建出该类的实例化对象,否则这个值又赋给谁呢?同样的,使用get方法时也要传入该类的实例化对象,否则不知道获取哪个对象的成员变量值。
注意:我们在获得构造器和成员变量的时候均不用setAccessible方法,而是在使用构造器实例化对象和使用成员变量赋值的时候,对于私有的构造器和成员变量才要使用setAccessible方法。成员方法也和上述一样。
package com.njau.d2_reflect;import org.junit.Test;import java.lang.reflect.Field;/*** 目标:掌握获取类的成员变量* Class提供了从类中获取成员变量的方法* public Field[] getFields() 获取类的全部成员变量(只能获取public修饰的)* public Field[] getDeclaredFields() 获取类的全部成员变量(只要存在就能拿到)* public Field getField() 获取类的某个成员变量(只能获取public修饰的)* public Field getDeclaredField() 获取类的全部成员变量(只要存在就能拿到)* 获取到成员变量的作用:依然是赋值,取值* void set(Object obj,Object value) 赋值* Object get(Object obj) 取值* public void setAccessible(boolean flag) 设置为true,表示禁止检查访问控制(暴力反射)*/public class Test3Field {@Testpublic void testGetFields() throws Exception {// 1、反射第一步:首先获取到类Class对象Class c = Cat.class;// 2、public Field[] getFields() 获取类的全部成员变量(只能获取public修饰的)
// Field[] fields = c.getFields();Field[] fields = c.getDeclaredFields(); // 获取类的全部成员变量(只要存在就能拿到)for (Field field : fields) {System.out.println(field.getName() + "--->" + field.getType());}// 3、public Field getField(String name) 获取类的某个成员变量(只能获取public修饰的)Field fName = c.getDeclaredField("name");System.out.println(fName.getName() + "--->" + fName.getType()); // name--->class java.lang.String// 4、public Field getDeclaredField(String name) 获取类的某个成员变量(只要存在就能拿到)Field fAge = c.getDeclaredField("age");System.out.println(fAge.getName() + "--->" + fAge.getType()); // age--->int}@Testpublic void testSetAndGet() throws Exception {Class c = Cat.class;Cat cat = new Cat();
// 获取某个类的成员变量Field fName = c.getDeclaredField("name");
// public void setAccessible(boolean flag) 设置为true,表示禁止检查访问控制(暴力反射)fName.setAccessible(true); // 禁止访问控制权限
// void set(Object obj,Object value) 赋值fName.set(cat, "招财猫");
// Object get(Object obj) 取值String name = (String) fName.get(cat);System.out.println(name);System.out.println(cat);Field fAge = c.getDeclaredField("age");
// public void setAccessible(boolean flag) 设置为true,表示禁止检查访问控制(暴力反射)fAge.setAccessible(true);
// void set(Object obj,Object value) 赋值fAge.set(cat,3);
// Object get(Object obj) 取值int age = (int) fAge.get(cat);System.out.println(age);System.out.println(cat);}
}
调用get方法时并不知道返回的成员变量类型,因此java官方为我们设定了Object类型。但是我们要将其进行强制转换。
二.获取类的成员方法
package com.njau.d2_reflect;public class Cat {public static int a;public static final String COUNTRY = "中国";private String name;private int age;public Cat(String name, int age) {System.out.println("有参数构造器执行了!");this.name = name;this.age = age;}public Cat() {System.out.println("无参构造器执行了!");}public String getName() {return name;}private void run() {System.out.println("🐱跑的贼快~~");}public void eat() {System.out.println("🐱爱吃猫粮~~");}// 方法的重载private String eat(String name) {return "🐱爱吃" + name;}public void setName(String name) {this.name = name;}public int getAge() {return age;}public void setAge(int age) {this.age = age;}@Overridepublic String toString() {return "Cat{" +"name='" + name + '\'' +", age=" + age +'}';}
}

* Method[] getMethods() 获取类的全部成员方法(只能获取public修饰的)
* Method[] getDeclaredMethods() 获取类的全部成员方法(只要存在就能获取)
* Method[] getMethod(String name,Class<?> ... parameterTypes) 获取类的某个成员方法(只能获取public修饰的)
* Method[] getDeclaredMethod(String name,Class<?> ... parameterTypes) 获取类的某个成员方法(只要存在就能获取)
首先我们要获取类的成员方法,就要先获取类对象。因此反射的第一步永远都是获取类对象。
package com.njau.d2_reflect;import org.junit.Test;import java.lang.reflect.Method;/*** 目标:获取类的成员方法* Method[] getMethods() 获取类的全部成员方法(只能获取public修饰的)* Method[] getDeclaredMethods() 获取类的全部成员方法(只要存在就能获取)* Method[] getMethod(String name,Class<?> ... parameterTypes) 获取类的某个成员方法(只能获取public修饰的)* Method[] getDeclaredMethod(String name,Class<?> ... parameterTypes) 获取类的某个成员方法(只要存在就能获取)* 成员方法的作用:依然是执行* public Object invoke(Object obj, Object ... args) 出发某个对象的该方法执行 Object obj代表类的某个实例对象* public void setAccessible(boolean flag) 设置为true,表示禁止检查访问控制(暴力反射)*/
public class Test4Method {@Testpublic void testGetDeclaredMethods() throws Exception {// 1、反射第一步:首先获取Class对象Class c = Cat.class;// 2、获取类的全部成员方法Method[] methods = c.getDeclaredMethods();// 3、对所有成员方法进行遍历for (Method method : methods) {System.out.println(method.getName() + "--->" + method.getParameterCount()+ "--->" + method.getReturnType());}// 4、获得某个成员方法Method run = c.getDeclaredMethod("run");System.out.println(run.getName() + "--->" + run.getParameterCount()+ "--->" + run.getReturnType()); // run--->0--->voidMethod eat = c.getDeclaredMethod("eat",String.class);System.out.println(eat.getName() + "--->" + eat.getParameterCount()+ "--->" + eat.getReturnType()); // eat--->1--->class java.lang.String}
}
我们使用getDeclaredMethods()方法来获取类中的全部实例对象。然后用Method类型的数据对其进行封装。封装后我们进行遍历,在遍历时我们可以使用:
1.getName()方法获得该方法的方法名
2.getParameterCount()方法获得该方法的参数个数
3.getReturnType()方法获得该方法的返回值类型
我们使用getDeclaredMethod(String name,Class<?> ... parameterTypes)方法来获取类中的指定的实例对象。其中要获得指定的方法吗,就要在name字段指定方法名,在Class<?> ... parameterTypes字段指定参数类型。
通过反射获得成员方法的作用依然是执行
* public Object invoke(Object obj, Object ... args) 出发某个对象的该方法执行 Object obj代表类的某个实例对象
* public void setAccessible(boolean flag) 设置为true,表示禁止检查访问控制(暴力反射)
我们可以在获得成员方法对象后通过invoke方法执行该成员方法。但是在使用invoke方法之前,我们首先要new一个该方法所在类的实例化对象,因为这个成员方法是该类的成员方法,是通过该类的实例化对象进行调用的。因此要先将该类实例化对象出来,再将该对象传入invoke方法里才能够进行调用。
package com.njau.d2_reflect;import org.junit.Test;import java.lang.reflect.Method;/*** 目标:获取类的成员方法* Method[] getMethods() 获取类的全部成员方法(只能获取public修饰的)* Method[] getDeclaredMethods() 获取类的全部成员方法(只要存在就能获取)* Method[] getMethod(String name,Class<?> ... parameterTypes) 获取类的某个成员方法(只能获取public修饰的)* Method[] getDeclaredMethod(String name,Class<?> ... parameterTypes) 获取类的某个成员方法(只要存在就能获取)* 成员方法的作用:依然是执行* public Object invoke(Object obj, Object ... args) 出发某个对象的该方法执行 Object obj代表类的某个实例对象* public void setAccessible(boolean flag) 设置为true,表示禁止检查访问控制(暴力反射)*/
public class Test4Method {@Testpublic void testGetDeclaredMethods() throws Exception {// 1、反射第一步:首先获取Class对象Class c = Cat.class;// 2、获取类的全部成员方法Method[] methods = c.getDeclaredMethods();// 3、对所有成员方法进行遍历for (Method method : methods) {System.out.println(method.getName() + "--->" + method.getParameterCount()+ "--->" + method.getReturnType());}// 4、获得某个成员方法Method run = c.getDeclaredMethod("run");System.out.println(run.getName() + "--->" + run.getParameterCount()+ "--->" + run.getReturnType()); // run--->0--->voidMethod eat = c.getDeclaredMethod("eat",String.class);System.out.println(eat.getName() + "--->" + eat.getParameterCount()+ "--->" + eat.getReturnType()); // eat--->1--->class java.lang.StringCat cat = new Cat(); // 创建一个猫对象run.setAccessible(true); // 表示禁止检查访问控制(暴力反射)Object object = run.invoke(cat); // 🐱跑的贼快~~System.out.println(object); // null 没有返回值,就是nulleat.setAccessible(true);String food = (String) eat.invoke(cat, "鱼儿");System.out.println(food);}
}
我们使用获取到的成员方法对象run调用invoke方法执行run方法,在调用invoke方法前我们实例化一个Cat类对象cat,并将该对象传入invoke方法中,又因为run方法没有参数,因此不需要传递参数。也没有返回值,因此返回值为null。java官方并不知道我们的方法返回值类型是什么,因此统一使用Object进行接收。
同样的,在调用eat的重载方法时,有一个参数String类型的,因此要传入一个字符串。且返回值是一个字符串,因此要使用String类型的变量接收并打印出来。
当我们在调用invoke进行方法的执行时,由于我们的方法在定义时都是用private修饰的,因此再调用invoke执行该方法时会出现权限不够,因此要使用setAccessible()方法将其设置为true。才能保证正常执行。
执行结果: