javase-反射

58 阅读4分钟

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

  • 获取:获取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

在这里插入图片描述

获取构造方法

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

在这里插入图片描述

获取成员变量

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

在这里插入图片描述

获取成员方法

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:私有的