反射

158 阅读3分钟

什么是反射?

(反射通俗一点说就是把一个类里面的信息扒得赤裸裸的,一点都没有残余)

注意: 反射允许对成员变量,成员方法和构造方法的信息进行编程访问,我的理解:把反射当成为一个人,这个人可以把一个类里面的所有信息拿出来就是反射。在现实生活中经常用到反射,比如说idea中自动提示的功能其实就是利用反射实现的,还有就是idea中ctrl+p的提示功能也利用了反射。

反射分为两类:

  • 获取:从class字节码文件中获取类中的所有信息
  • 解剖:解剖要在获取的基础之上操作,先要获取才能得已解剖

获取class对象的三种方式: Class.forName("全类名"); 把.java文件变成.class文件(并没有加载到内存中) 源代码阶段 类名.class 加载到内存中 加载阶段 对象.getClass(); 运行阶段 创建对象new一个对象

反射获取构造方法:

  • Constrctor<?>[] getConstructors():返回所有公共构造方法对象的数组
  • Constrctor<?>[] getDeclareConstructors():返回所有构造方法对象的数组
  • Constrctor<T>[] getConstructor(Class<?>...parameterTypes):返回单个构造方法对象
  • Constrctor<T>[] getDeclareConstructor(Class<?>...parameterTypes):返回单个构造方法对象

反射获取:

先创建一个实体类:

    public class Student {
    
    private String name;
    private int age;

    public Student() {
    }

    public Student(String name){
        this.name=name;
    }

    protected Student(int age){
        this.age=age;
    }

    private Student(String name, int age) {
        this.name = name;
        this.age = age;
    }

    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;
    }

    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + ''' +
                ", age=" + age +
                '}';
    }
}

再创建一个测试类(获取的东西都在代码可见):

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Parameter;

public class MyReflectDemo {
    public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
        //1.获取class字节码文件对象
        Class clazz = Class.forName("com.atguigu1.Student");
        //获取了字节码文件之后,类中所有的内容都可以取出来
        //2.获取构造方法
        //获取所有
        Constructor[] cons = clazz.getConstructors();
        for (Constructor con : cons) {
            System.out.println(con);
        }
        //获取所有
        Constructor[] cons2 = clazz.getDeclaredConstructors();
        for (Constructor con : cons2) {
            System.out.println(con);
        }
        //获取单个
        Constructor con1 = clazz.getDeclaredConstructor();
        System.out.println(con1);
        //获取单个(有参数)
        Constructor con2 = clazz.getDeclaredConstructor(String.class);
        System.out.println(con2);
        //获取单个(有参数)
        Constructor con3 = clazz.getDeclaredConstructor(int.class);
        System.out.println(con3);
        //获取两个参数的
        Constructor con4 = clazz.getDeclaredConstructor(String.class, int.class);
        System.out.println(con4);

        //获取权限修饰符
        int modifiers = con4.getModifiers();
        System.out.println(modifiers);
        //获取参数
        Parameter[] parameters = con4.getParameters();
        for (Parameter parameter : parameters) {
            System.out.println(parameter);
        }

        /*Student stu = (Student) con4.newInstance("张三", 23);
        System.out.println(stu);
        报错,虽然用了declare,但是也只是能够我们看到,不能使用,没有实际意义,如果要进行使用,需要进行暴力反射*/

        //暴力反射:表示临时取消权限校验
        con4.setAccessible(true);
        Student stu = (Student) con4.newInstance("张三", 23);
        System.out.println(stu);
    }
}

反射获取成员变量:

与反射获取构造器大同小异,只是多出了

void set(Object obj,Object value):赋值

Pbject get(Object obj):获取值

反射获取成员方法:

与反射获取构造器大同小异,只是多了一点点东西:

Method类中用于创建对象的方法:

Object invoke(Object obj,Object... args):运行方法

  • 参数一:用obj对象调用该方法
  • 参数二:调用方法的传递的参数(如果没有就不写)
  • 返回值:方法的返回值(如果没有就不写)
clazz.getMethods();//获取里面所有的的方法对象(包含父类中所有的公共的方法)

clazz.getDeclareMethods();//(不能获取父类的,但是可以获取本类中私有的)

clazz.getDeclareMethod("方法名",参数的字节码类型);//获取指定的单一方法

对象名.getExceptionTypes();//获取方法的抛出的异常

总结:

反射的作用

  1. 反射可获取一个类里面的所有的信息,获取到了之后,再执行其他的业务逻辑
  2. 反射可以结合配置文件,动态的创建对象并调用方法(好处就是不用修改代码,而直接修改配置文件)
  3. 反射获取构造方法、成员方法以及成员变量汇总:
方法名行为
get获取
set设置
Constructor构造方法
Parameter参数
Field成员变量
Modifiers修饰符
Method方法
Declared私有的