Java的反射

262 阅读5分钟

Java 反射

1、什么是反射?

反射 允许对封装类的字段,方法 和 构造函数的信息进行编程访问。(就是可以从类里面拿东西)

反射可以得到类的(获取)(从class字节码文件中获取,所以需要先得到类的字节码文件对象)功能(解刨)
字段(成员变量)获取修饰符、获取名字、获取类型、赋值/获取值
构造方法获取修饰符、获取名字、获取形参、创建对象
成员方法获取修饰符、获取名字、获取形参、获取返回值、抛出的异常、获取注解、运行方法

2、获取class对象的三种方式

① Class.forName("全类名"); 源代码阶段

②类名 . Class 加载阶段

③对象 . getClass(); (定义在Object这个类中的方法,所以所有对象都有这个方法) 运行阶段

源代码阶段.java文件通过 javac 编译成 .class文件
加载阶段.class 文件在内存中 加载
运行阶段在内存中创建类的对象
获得class 字节码对象
      //全类名   com.xxl.job.admin.fanshe.Student
        Class<?> aClass = Class.forName("com.xxl.job.admin.fanshe.Student");
//        System.out.println("aClass = " + aClass);
        Class<Student> studentClass = Student.class;
//        System.out.println("studentClass = " + studentClass);
        Student student = new Student();
        Class<? extends Student> aClass1 = student.getClass();
//        System.out.println("aClass1 = " + aClass1);

3、反射获取 构造方法

/**
         * Class 类中用于获取构造器对象的方法
         * Constructor<?>[] getConstructors();  返回所有公共构造方法对象的数组  (公共表示public修饰的构造方法)
         * Constructor<?>[] getDeclaredConstructors();返回所有构造方法对象的数组
         * Constructor<T> getConstructor(Class<?>... parameterTypes);返回单个公共构造方法对象  (公共表示public修饰的)
         * Constructor<T> getDeclaredConstructor(Class<?>... parameterTypes);返回单个构造方法对象
         *
         *
         * Constructor类中用于创建对象的方法
         * T newInstance(Object... initargs);  根据指定的构造方法创建对象
         * setAccessible(boolean flag);设置是否允许访问,私有的属性、方法、构造器都可以访问  true表示允许访问,取消访问检查
         *
         */

        //利用字节码文件来获取构造方法的  aClass
         //获取所有的公共的构造方法
        Constructor<?>[] cons = aClass.getConstructors();
        for (Constructor<?> con : cons) {
            System.out.println("con = " + con);
        }




        //获取所有的 连带私有的
        Constructor<?>[] dec = aClass.getDeclaredConstructors();
        for (Constructor<?> constructor : dec) {
            System.out.println("constructor = " + constructor);
        }


        //获取单个的公共的构造方法
       Constructor<?> constructor = aClass.getConstructor();
        System.out.println("constructor = " + constructor);

        //获取单个指定 任意 参数的构造方法
        Constructor<?> dc = aClass.getDeclaredConstructor(int.class);
        System.out.println("declaredConstructor = " + dc);


3.1、获取权限修饰符的方法

public 对应 1 private 对应 2

protected 对应 4

        int modifiers = dc.getModifiers();  // 获取构造方法的修饰符
        System.out.println("modifiers = " + modifiers);  //输出2

3.2、获取构造方法的参数并分析

getParameters()  //获取所有的参数
getParameterCount()   //获得参数的个数
getParameterType()   //获得参数的类型

3.3、对于私有的构造函数进行创建对象

//假设 dc 是通过 getDeclaredConstructor(String.Class)得到的私有的带有String 类型的构造函数
       dc.setAccessible(true);  // 表示临时允许访问,取消访问检查  !!!
        Object o = dc.newInstance(6);
        System.out.println("o = " + o);

4、反射获取 成员变量


 /**
         * 利用反射获取成员变量
         * Class类中用于获取成员变量的方法
         * Filed[] getFields();返回所有公共成员变量对象(public修饰的)的数组
         * Filed[] getDeclaredFields();返回所有成员变量对象的数组
         * Filed getField(String name);返回单个公共成员变量对象(public修饰的)
         * Filed getDeclaredField(String name);返回单个成员变量对象
         *
         * Filed类中用于创建对象的方法
         * void set(Object obj, Object value);为对象变量赋值
         * Object get(Object obj);获取对象变量的值
         */

        //利用反射 获取目标对象的成员变量
        //1、获取目标对象的字节码文件对象
        Class<?> stu = Class.forName("com.xxl.job.admin.fanshe.Student");
        //获取 公共的 成员变量
        Field[] fields = stu.getFields();
        for (Field field : fields) {
            System.out.println("field = " + field);
        }

        //获取所有的 包括私有的 成员变量
        Field[] declaredFields = stu.getDeclaredFields();
        for (Field declaredField : declaredFields) {
            System.out.println("declaredField = " + declaredField);
        }

        //获取单个的
        Field name = stu.getField("name");
        System.out.println("name = " + name);

        //获取单个的私有的
        Field sex = stu.getDeclaredField("sex");
        System.out.println("sex = " + sex);

        //获取成员变量的修饰符
        int modifiers = sex.getModifiers();
        System.out.println("modifiers = " + modifiers);

        //获取成员变量名
        String name1 = sex.getName();
        System.out.println("name1 = " + name1);

        //获取成员变量的类型
        Class<?> type = sex.getType();
        System.out.println("type = " + type);

        //获取成员变量记录的值
        Student student = new Student(6, "李龙", "男");
        sex.setAccessible(true);   //因为sex 是私有的,所以需要取消访问检查
        Object o = sex.get(student);
        System.out.println("o = " + o);
        System.out.println("student = " + student);

        //修改值 改为女
        sex.set(student, "女");
        System.out.println("student = " + student);


5、反射获取 成员方法


/**
         * 利用反射获取成员方法的方法
         * Method[] getMethods();返回所有公共成员方法对象的数组(public修饰的) (包括父类中的 继承的)
         * Method[] getDeclaredMethods();返回所有成员方法对象的数组(包括私有的) 不包括父类中的继承的
         * Method getMethod(String name, Class<?>... parameterTypes);返回单个公共成员方法对象(包括父类中的继承的)
         * Method getDeclaredMethod(String name, Class<?>... parameterTypes);返回单个成员方法对象 (包括私有的)不包括父类中的继承的
         *
         *
         * Method类中用于创建对象的方法
         * Object invoke(Object obj, Object... args);运行方法
         * 参数1:要调用方法的对象
         * 参数2:要调用方法的参数(没有就不写)
         * 返回值 :方法的返回值 如果方法没有返回值,就不写
         */

        //获取字节码对象
        Class<?> cs = Class.forName("com.xxl.job.admin.fanshe.Student");
        //获取类中的所有的方法对象 包含父类中所有的
        Method[] methods = cs.getMethods();
        for (Method method : methods) {
            System.out.println("method = " + method);
        }

        //获取单个的
        Method method = cs.getMethod("sleep");
        System.out.println("获取单一的方法 = " + method);

        //获得方法的修饰符
        int modifiers = method.getModifiers();
        System.out.println("modifiers = " + modifiers);

        //获取方法的名字
        String name = method.getName();
        System.out.println("方法名字 = " + name);

        //获得方法的形参
        Method eat = cs.getDeclaredMethod("eat",String.class);
        Parameter[] parameters = eat.getParameters();
        for (Parameter parameter : parameters) {
            System.out.println("parameter = " + parameter);
        }
//        getParameters()  //获取所有的参数
//        getParameterCount()   //获得参数的个数
//        getParameterType()   //获得参数的类型

        //获得方法抛出的异常
        Class<?>[] exceptionTypes = eat.getExceptionTypes();
        for (Class<?> exceptionType : exceptionTypes) {
            System.out.println("exceptionType = " + exceptionType);
        }

        //运行得到的方法
        Student student = new Student(6, "李龙", "男");
        //参数一:方法的调用者
        //参数二:方法参数  没有就不写
        //返回值 没有就不写
        eat.setAccessible(true);
        Object result = eat.invoke(student, "李兄");
        System.out.println("方法的返回值 = " + result);