一、什么是反射机制

Java反射机制指的是在Java程序运行状态中,对于任何一个类,都可以获得这个类的所有属性和方法;对于给定的一个对象,都能够调用它的任意一个属性和方法。这种动态获取类的内容以及动态调用对象的方法称为反射机制。

二、反射机制的原理

反射机制(Reflection)是Java提供的一项较为高级的功能,它提供了一种动态功能,而此功能的体现在于通过反射机制相关的API就可以获取任何Java类的包括属性、方法、构造器、修饰符等信息。元素不必在JVM运行时进行确定,反射可以使得它们在运行时动态地进行创建或调用。

三、反射功能实现

Class类、Field类、Method类、Constructor类与反射功能的实现相关。

1、类对象:Class

Student

package com.wedu.test;

public class Student {
    //名字
    private String name;
    //年龄
    private int age;

    public Student() {
    }

    public 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 +
                '}';
    }
}

      a、class对象的获取方式

package com.wedu.test;

/**
 * 获取Class类对象的方式
 */
public class Demo {
    public static void main(String[] args) throws Exception {
        //1、Class.forName("全类名"):将字节码文件加载进内存,返回Class对象;多用于配置文件
        Class cls1 = Class.forName("com.wedu.test.Student");

        //2、类名.class:通过类名的属性class获取;多用于参数的传递
        Class cls2 = Student.class;

        //3、对象.getClass():getClass()方法在Object类中定义着;多用于对象的获取字节码的方式
        Student student = new Student();
         Class cls3 = student.getClass();

        System.out.println(cls1 == cls2);//true
        System.out.println(cls1 == cls3);//true
    }
}

  b、class对象功能

        获取成员变量Field及其操作

package com.wedu.test;

import java.lang.reflect.Field;

/**
 * 获取成员变量Field
 */
public class Demo {
    public static void main(String[] args) throws Exception {
        Class cls = Student.class;

        //public Field[] getFields():获取所有public修饰的成员变量
        Field[] fields = cls.getFields();
        for (Field field : fields) {
            System.out.println(field);
        }

        //public Field getField(String name):获取指定public修饰的成员变量
        Field name = cls.getField("name");
        System.out.println(name.getName());

        //public Field[] getDeclaredFields():获取所有的成员变量,不考虑修饰符
        fields = cls.getDeclaredFields();
        for (Field field : fields) {
            System.out.println(field);
        }

        //public Field getDeclaredField(String name):获取指定的成员变量,不考虑修饰符
        Field age = cls.getDeclaredField("age");
        System.out.println(age.getName());

        //public T newInstance():创建此 Class 对象所表示的类的一个新实例。
        Student student = (Student) cls.newInstance();

        //public void set(Object obj, Object value):设置属性的值
        name.set(student,"张三");

        //public Object get(Object obj):获取属性的值
        System.out.println(name.get(student));

        //public void setAccessible(boolean flag) 忽略访问权限修饰符的安全检查
        age.setAccessible(true);
        age.set(student,25);
        System.out.println(student);
    }
}

   获取构造方法Constructor及其操作

package com.wedu.test;

import java.lang.reflect.Constructor;

/**
 * 获取构造方法Constructor
 */
public class Demo {
    public static void main(String[] args) throws Exception {
        //获取Student的Class对象
        Class cls = Student.class;

        //Constructor<?>[] getConstructors():获取public修饰的无参构造
        Constructor constructor = cls.getConstructor();
        System.out.println(constructor);
        //创建对象
        Object student = constructor.newInstance();
        System.out.println(student);

        //Constructor<T> getConstructor(类<?>... parameterTypes):获取public修饰的有参构造
        constructor = cls.getConstructor(String.class, String.class, int.class, int.class);
        System.out.println(constructor);

        //创建对象
        student = constructor.newInstance("张三", "男",10000,28);
        System.out.println(student);

        //Constructor<?>[] getDeclaredConstructors():获取所有的无参构造
        constructor = cls.getDeclaredConstructor();
        System.out.println(constructor);
        //创建对象
        student = constructor.newInstance();
        System.out.println(student);

        //Constructor<T> getDeclaredConstructor(类<?>... parameterTypes):获取所有的有参构造
        constructor = cls.getDeclaredConstructor(String.class, String.class, int.class, int.class);
        System.out.println(constructor);

        //创建对象
        student = constructor.newInstance("李四", "男",15000,30);
        System.out.println(student);
    }
}

  注意:如果需要通过私有构造方法创建对象,需要设置忽略访问权限修饰符的安全检查,即:

设置constructor.setAccessible(true)后,才能使用私有构造创建对象。

获取成员方法Method及其操作

package com.wedu.test;

import java.lang.reflect.Method;

/**
 * 获取成员方法Method
 */
public class Demo {
    public static void main(String[] args) throws Exception {
        //获取Student的Class对象
        Class cls = Student.class;

        //Method[] getMethods() 获取所有public修饰的方法
        Method[] methods = cls.getMethods();
        for (Method method : methods) {
            System.out.println(method);
            String name = method.getName();
            System.out.println(name);
        }

        //public Method getMethod(String name, Class<?>... parameterTypes):获取指定public修饰的方法
        Method method = cls.getMethod("setName", String.class);
        System.out.println(method);

        //public Method[] getDeclaredMethods():获取所有的方法
        methods = cls.getDeclaredMethods();
        for (Method method1 : methods) {
            System.out.println(method1);
            String name = method1.getName();
            System.out.println(name);
        }

        //public Method getMethod(String name, Class<?>... parameterTypes):获取指定public修饰的方法
        method = cls.getMethod("setName", String.class);
        System.out.println(method);

        //执行方法
        Student student = (Student)cls.newInstance();
        method.invoke(student,"张三");
        Method getName = cls.getMethod("getName");
        Object value = getName.invoke(student);
        System.out.println(value);

    }
}

四、反射应用

使用反射方式编写框架类

1、编写配置文件pro.properties

className=com.wedu.reflect.entity.Student
methodName=sleep

2、通过反射方式编写框架类

package com.wedu.reflect.demo;

import java.io.InputStream;
import java.lang.reflect.Method;
import java.util.Properties;

/**
 * @description: 使用反射方式编写框架类
 * @author YuanHang
 * @date 2021-09-11 11:52
 */
public class ReflectTest {
    public static void main(String[] args) throws Exception {
        //1.加载配置文件
        //1.1创建Properties对象
        Properties pro = new Properties();
        //1.2加载配置文件,转换为一个集合
        //1.2.1获取class目录下的配置文件
        ClassLoader classLoader = ReflectTest.class.getClassLoader();
        InputStream is = classLoader.getResourceAsStream("pro.properties");
        pro.load(is);

        //2.获取配置文件中定义的数据
        String className = pro.getProperty("className");
        String methodName = pro.getProperty("methodName");


        //3.加载该类进内存
        Class cls = Class.forName(className);
        //4.创建对象
        Object obj = cls.newInstance();
        //5.获取方法对象
        Method method = cls.getMethod(methodName);
        //6.执行方法
        method.invoke(obj);
    }
}