反射允许对成员变量,成员方法、构造方法的信息进行编程访问。
反射 = 获取 + 解剖

  • 获取:获取class对象
  • 解剖:解剖class对象的一些方法信息

获取class对象的三种方式

  • Class.forName(“全类名”):最常用。
  • 类名.class:当作参数进行传递
  • 对象.getClass():当已经有了这个类的对象时可以使用
@Data
@AllArgsConstructor
@NoArgsConstructor
class Student {
private String name;
private int age;
}
public class Demo01 {
public static void main(String[] args) throws ClassNotFoundException {
// Class.forName("全类名")
Class clazz1 = Class.forName("com.atguigu.reflect.reflect_01_get.Student");// 全类名 = 包名 + 类名
// 类名.class
Class clazz2 = Student.class;
// 对象.getClass()
Student stu = new Student();
Class clazz3 = stu.getClass();
}
}

利用反射获取构造方法Constructor

ddcb8d18273a47d9a97f16a5da85b511.png

获取构造方法

class Stu {
private String name;
private int age;
public Stu() {}
public Stu(String name) {
this.name = name;
}
protected Stu(int age) {
this.age = age;
}
private Stu(String name, int age) {
this.name = name;
this.age = age;
}
}
public class Demo02 {
public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException {
// 获取字节码文件对象
Class clazz = Class.forName("com.atguigu.reflect.reflect_01_get.Stu");
// 获取所有公共的构造方法
Constructor[] cons1 = clazz.getConstructors();
// 获取所有的构造方法
Constructor[] cons2 = clazz.getDeclaredConstructors();
// 获取单个构造方法对象【只能获取公共的】
Constructor con1 = clazz.getConstructor();
Constructor con2 = clazz.getConstructor(String.class);
// 获取单个构造方法对象
Constructor con3 = clazz.getDeclaredConstructor(int.class);
Constructor con4 = clazz.getDeclaredConstructor(String.class, int.class);
System.out.println(con4);
}
}

获取权限修饰符

getDeclaredConstructor()如果获取的是私有的构造方法,正常情况不能用获取的构造方法创建对象,但是使用暴力反射就可以使用私有的构造方法创建对象了

Constructor con = clazz.getDeclaredConstructor(String.class, int.class);
con.setAccessible(true);
Stu stu = (Stu) con.newInstance("zhangsan", 23);
public class Demo03 {
public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
// 获取字节码文件对象
Class clazz = Class.forName("com.atguigu.reflect.reflect_01_get.Stu");
// 获取构造方法对象【私有的】
Constructor con = clazz.getDeclaredConstructor(String.class, int.class);
// 创建对象
// 暴力反射:临时取消权限校验【如果使用私有的构造方法,需要加上这行】
con.setAccessible(true);
Stu stu = (Stu) con.newInstance("zhangsan", 23);

// 获取构造方法的权限修饰符
int modifiers = con.getModifiers();

// 获取构造方法的参数
Parameter[] ps = con.getParameters();
}
}

利用反射获取成员变量Field

200774045d0b4aaa8d4fd770a9ad92ec.png

获取成员变量

class Stu2 {
private String name;
private int age;
public String gender;
}
public class Demo04 {
public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException {
// 获取class字节码文件对象
Class clazz = Class.forName("com.atguigu.reflect.reflect_01_get.Stu2");
// 获取所有公共的成员变量
Field[] fields1 = clazz.getFields();
// 获取所有的成员变量
Field[] fields2 = clazz.getDeclaredFields();
// 获取公共的单个成员变量
Field gender = clazz.getField("gender");
// 获取单个成员变量
Field name = clazz.getDeclaredField("name");
}
}

获取权限修饰符

public class Demo05 {
public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException, IllegalAccessException {
// 获取字节码文件对象
Class clazz = Class.forName("com.atguigu.reflect.reflect_01_get.Stu");
// 获取单个成员变量
Field name = clazz.getDeclaredField("name");
// 获取成员变量记录的值
// 暴力反射:临时取消权限校验【如果要获取私有的成员变量,需要加上这行】
name.setAccessible(true);
Stu stu = new Stu();
String value = (String) name.get(stu);

// 修改成员变量的值
name.set(stu, "linsan");

// 获取修饰符
int modifiers = name.getModifiers();

// 获取成员变量名
String n = name.getName();

// 获取数据类型
Class<?> type = name.getType();
}
}

利用反射获取成员方法Method

034ce5f995e2439daf61435975e0e494.png

获取成员方法

class Stu3 {
public void sleep() {
System.out.println("睡觉");
}
private String eat(String something) {
System.out.println("在吃" + something);
return something;
}
private void eat(String something, int a) throws IOException {
System.out.println("在吃" + something);
}
}
public class Demo06 {
public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException {
Class clazz = Class.forName("com.atguigu.reflect.reflect_01_get.Stu3");
// 获取所有公共的方法【包含父类中所有的公共方法】
Method[] methods1 = clazz.getMethods();
// 获取所有本类中的方法【包括私有方法】
Method[] methods2 = clazz.getDeclaredMethods();
// 获取公共的方法
Method sleep = clazz.getMethod("sleep");
// 获取指定的单一方法
Method eat = clazz.getDeclaredMethod("eat", String.class, int.class);
}
}

获取权限修饰符

public class Demo07 {
public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, IllegalAccessException {
Class clazz = Class.forName("com.atguigu.reflect.reflect_01_get.Stu3");
Method eat = clazz.getDeclaredMethod("eat", String.class);
// 获取方法的修饰符
int modifiers = eat.getModifiers();
// 获取方法的名字
String name = eat.getName();
// 获取方法的形参
Parameter[] parameters = eat.getParameters();
// 获取方法抛出的异常
Class<?>[] exceptionTypes = eat.getExceptionTypes();
/**
* 运行方法:
* Object invoke(Object obj, Object... args):运行方法
* 参数1:用obj对象调用该方法
* 参数2:调用方法的传递的参数(如果没有就不写)
* 返回值:方法的返回值(如果没有就不写)
*/
Stu3 stu = new Stu3();
eat.setAccessible(true); // 取消访问权限
String res = (String) eat.invoke(stu, "火锅");
}
}

反射的作用

  1. 获取一个类里面所有的信息,获取到之后,再执行其他的业务逻辑
  2. 结合配置文件,动态的创建对象并调用方法

总结:

  • get:获取
  • set:设置
  • Constructor:构造方法
  • Field:成员变量
  • Method:方法
  • Parameter:参数
  • Modifiers:修饰符
  • Declared:私有的