JAVA反射机制

说一下你对java反射机制的理解?
  • java反射机制就是在程序运行期间,可以动态获取任意一个类的任意属性和方法、调用任意一个对象的任意属性和方法。这种动态获取信息和动态调用对象方法的功能,被称为java语言的反射机制
java运行流程
  • 在我们编写好xx.java源文件后,javac编译器会将xx.java源文件编译成xx.class字节码文件。然后通过jvm的ClassLoader类加载器将其加载到jvm中。在运行期间,jvm拿到xx.class后,就可以动态获得xx这个类,以及这个类的属性和方法,并且可以通过这个类动态生成这个类的对象实例。

JAVA反射机制_第1张图片

java反射机制的作用
  • java反射一般用来编写一些通用性较高的代码 或者 在框架中使用。比如spring ioc的底层就是用了java反射(java反射+工厂+配置文件),我们在spring配置文件中配置了类后,就可以通过反射动态生成这个类的具体对象,调用这个类的方法。
java反射机制 - 反射API
  • Class

    Class类的实例:表示正在运行的java程序的类和接口(class字节码文件被加载到内存所形成的一个对象)

  • Constructor

    类的单个构造方法的信息,以及对它的动态访问权限

  • Field

    Field提供有关类的或接口上单个字段的信息,以及对它的动态访问权限

  • Method

    Method提供有关类或接口上单独某个方法的信息

获取类Class对象有几种方式方式

在一个jvm中,一个类只有一个类对象存在,所以通过下面三种方式获取类对象都是一样的。

  • 已知类和对象的情况下

    类名.class 如:person.class

    对象.getClass() 如:new person.getClass()

  • 未知类和对象的情况下

    Class.forName(“包名+类名”) 如:Class.forName(com.cd.entity.Person)

java中的java.lang.Class类用于表示一个类的字节码(.class)文件,内部提供了加载字节码的方法forName(“包名+类名”),forName()方法用于加载类字节码到内存中,并封装成一个Class对象。

import com.cd.entity.Person;
import org.junit.Test;

/**
 * @Author: 落叶无痕
 * @Date: 2020/4/18 12:33
 */
public class ClassTest {

    /**
     * 获取Class对象
     * * 1.类名.class
     * * 2.对象.getClass()
     * * 3.Class.forName("包名+类名")   (推荐)
     */
    @Test
    public void demo1() throws ClassNotFoundException {
        // 1.通过类名.class方式,得到class字节码文件被加载到内存后所形成的Class对象
        Class clazz1 = Person.class;
        // 2.通过对象.getClass()方式
        Person person = new Person();
        Class clazz2 = person.getClass();

        // 3.通过Class.forName("包名+类名")方式,(推荐使用该方式,因为做反射一般都是在不知道对象的情况下的,因为在对象的情况下,我们直接使用对象就好了)
        Class clazz3 = Class.forName("com.cd.entity.Person");

        System.out.println(clazz1 == clazz2);
        System.out.println(clazz1 == clazz3);
        System.out.println(clazz2 == clazz3);
    }

}

java反射中,获取到Person类的字节码对象(Class对象)后, 如何获得Person类的构造方法

import com.cd.entity.Person;
import org.junit.Test;

import java.lang.reflect.Constructor;

/**
 * @Author: 落叶无痕
 * @Date: 2020/4/18 13:02
 */
public class ConstructorTest {


    /*
      * 获取无参构造函数
     */
    @Test
    public void demo1() throws Exception {
        Class class1 = Class.forName("com.cd.entity.Person"); //获取类对象
        Constructor constructor = class1.getConstructor();    //获取无参构造函数
        Person person = (Person) constructor.newInstance();   //得到Person类的对象(这里相当于new了一个对象实例Person person = new Person();)
        person.doing(); //调用对象方法
    }
    

    /*
      * 获取有参构造函数
    */
    @Test
    public void demo2() throws Exception {
        Class class1 = Class.forName("com.cd.entity.Person"); //获取类对象
        Constructor constructor = class1.getConstructor(String.class, int.class);    //获取有参构造函数
        Person person = (Person) constructor.newInstance("张宇", 25);  //得到Person类的对象(这里相当于new了一个对象实例Person person = new Person();)
        person.doing(); //调用对象方法
    }

}

java反射 - 如何通过反射访问属性

java反射中通过Field类的set和get方法来操作属性。

  • set方法的第一个参数是要设置的对象,第二个参数是值。
  • get方法是要获取值的对象。
import com.cd.entity.Person;
import org.junit.Test;

import java.lang.reflect.Field;

/**
 * @Author: 落叶无痕
 * @Date: 2020/4/18 14:00
 */
public class FiledTest {


    /*
       * 操作共有属性  (其实共有属性没必要通过反射来操作,因为new了这个对象之后,我们可以直接通过该对象来操作的)
     */
    @Test
    public void demo1() throws Exception {
        // 获得Class
        Class class1 = Class.forName("com.cd.entity.Person");
        // 获得共有属性
        Field field = class1.getField("name");
        // 操作属性
        Person p = (Person) class1.newInstance();
        field.set(p, "张宇");

        Object object = field.get(p);
        System.out.println(object);
    }

    /*
       * 操作私有属性
     */
    @Test
    public void demo2() throws Exception {
        // 获得Class
        Class class2 = Class.forName("com.cd.entity.Person");
        // 获得私有属性
        Field ageField = class2.getDeclaredField("age");
        // 获得实例对象
        Person p = (Person) class2.newInstance();
        
        //操作私有属性,需要设置一个可访问的权限
        ageField.setAccessible(true);
        ageField.set(p, 25);
        Object age = ageField.get(p);
        System.out.println(age);

        //操作共有属性
        Field nameField = class2.getDeclaredField("name");
        nameField.set(p, "张宇");
        Object name = nameField.get(p);
        System.out.println(name);
    }

}
java反射机制 - 如何通过反射调用方法
  • Method类代表某个类的单独某个成员方法

  • Method对象提供了获取以下方法供我们获得指定类的方法

    • 获得所有方法

      getDeclaredMethods()

      getMethods()

    • 获得指定方法

      getDeclaredMethod(String name, Class . . . parameterTypes)

      • 第一个参数是方法名
      • 第二个参数参数列表中的参数类型

      getMethod(String name, Class . . . parameterTypes)

    • 推荐使用getDeclaredMethod()方法来获得方法。因为getDeclaredMethod可以获得所有类型的方法,而getMethod()只能获得共有类型的方法。

  • 获得Method对象后,我们就可以调用Method对象的invoke()方法来执行指定的方法。

import com.cd.entity.Person;
import org.junit.Test;

import java.lang.reflect.Method;

/**
 * @Author: 落叶无痕
 * @Date: 2020/4/19 0:19
 */
public class MethodTest {

    //测试共有方法
    @Test
    public void demo1() throws Exception {
        // 获得class字节码文件被加载到内存后形成的Class对象
        Class class1 = Class.forName("com.cd.entity.Person");
        // 创建对象实例
        Person p = (Person) class1.newInstance();
        // 获得类的单独某个方法
        Method method = class1.getMethod("doing");
        // 执行该方法
        method.invoke(p);  // 这里相当于p.doing(),doing()方法是公有方法
    }

    //测试私有方法
    @Test
    public void demo2() throws Exception {
        // 获得class字节码文件被加载到内存后形成的Class对象
        Class class2 = Class.forName("com.cd.entity.Person");
        // 创建对象实例
        Person p = (Person) class2.newInstance();
        // 获得私有方法
        Method method = class2.getDeclaredMethod("todo");
        // 设置私有属性的访问权限
        method.setAccessible(true);
        // 执行该方法
        method.invoke(p, null);
    }


    //测试带参方法
    @Test
    public void demo3() throws Exception {
        // 获得class字节码文件被加载到内存后形成的Class对象
        Class class3 = Class.forName("com.cd.entity.Person");
        // 创建对象实例
        Person p = (Person) class3.newInstance();
        // 获得该类的指定的某个方法
        Method method = class3.getDeclaredMethod("say", String.class, int.class);
        // 设置私有属性的访问权限
        method.setAccessible(true);
        // 执行该方法
        Object obj = method.invoke(p,"张宇", 25);
        System.out.println(obj);
    }

}

你可能感兴趣的:(Java,java,反射,spring,jvm)