反射的原理及应用

原理:反射首先是能够获取到Java中的反射类的字节码,然后将字节码中的方法,变量,构造函数等映射成 相应的 Method、Filed、Constructor 等类
应用:取出类的modifiers,数据成员,方法,构造器,和超类
找出某个接口里定义的常量和方法说明.
取得和设定对象数据成员的值,如果数据成员名是运行时刻确定的也能做到.
在运行时刻调用动态对象的方法.

1,类的加载

当程序要使用某个类时,如果该类还未被加载到内存中,则系统会通过加载,连接,初始化三步来实
现对这个类进行初始化。

  • 加载 就是指将 class 文件读入内存,并为之创建一个 Class 对象。 任何类被使用时系统都会建立一个 Class 对象
  • 连接 验证 是否有正确的内部结构,并和其他类协调一致 准备 负责为类的静态成员分配内存,并设置默认初始化值 解析 将类的二进制数据中的符号引用替换为直接引用
  • 初始化

1.2类的初始化

  1. 创建类的实例
  2. 类的静态变量,或者为静态变量赋值
  3. 类的静态方法
  4. 使用反射方式来强制创建某个类或接口对应的 java.lang.Class 对象
  5. 初始化某个类的子类

1.3反射概述

Java 反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称 为 java 语言的反射机制。

要想解剖一个类,必须先要获取到该类的字节码文件对象。而解剖这个类,使用的就是 Class 类中的方法,所以先要获取到每一个字节码文件所对应的 Class 类型对象。

1.4准备数据,我就用我现在的写的项目的数据,大家随意

反射的原理及应用_第1张图片

1.5 知识储备

需要掌握 6 个单词

  • Class 类
  • Constructor 构造
  • Method 方法
  • Filed 字段
  • instance 实例
  • invoke 执行

1.6 Class 获得方式

反射的原理及应用_第2张图片

public class A {
    /**
     * class获得方式
     *
     * @param args
     */
    public static void main(String[] args) {
        //1 通过类型获得
        // 语法:类名.class
        // 应用场景:确定类型 等
        Class clazz1 = BrandController.class;
        System.out.println("语法:类名.class|" + clazz1);

        //2 通过实例对象获得
        // 语法:变量.getClass()
        // 应用场景:在方法内部通过参数获得类型 等
        BrandController brandController = new BrandController();
        Class<? extends BrandController> aClass = brandController.getClass();
        System.out.println("语法:变量.getClass()|" + aClass);


        //3 通过字符串获得
        // 语法:Class.forName("全限定类名")
       // 应用场景:通过配置获得字符串 等
        try {
            Class<?> aClass1 = Class.forName("com.controller.BrandController");
            System.out.println("Class.forName(\"全限定类名\")|"+aClass1);
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }

    }


}

1.6.1 得到这个类的名字

反射的原理及应用_第3张图片

      //1 获得 Class
       Class clazz = User.class;
       // 得到这个类的名字:全限定类名
        String name = clazz.getName();
        //  这个只是类的名字
        String simpleName = clazz.getSimpleName();
        System.out.println(" 这个只是类的名字simpleName:"+simpleName);

        System.out.println("得到这个类的名字:全限定类名name:"+name);




1.7构造方法与实例

反射的原理及应用_第4张图片

public class A {
    /**
     * 构造方法与实例
     *
     * @param args
     */
    public static void main(String[] args) {
        //无参构造 , 并实例化

        //1 获得 Class
        Class<SpecificationOption> specificationOptionClass = SpecificationOption.class;
        System.out.println("获得 Class"+specificationOptionClass);
        //2 获得构造 -- 没有形参
        Constructor<SpecificationOption> constructor = null;
        try {
            constructor = specificationOptionClass.getConstructor();
            System.out.println("获得构造 -- 没有形参"+constructor);
            SpecificationOption specificationOption = constructor.newInstance();
            System.out.println("实例对象,没有实参"+specificationOption);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

获取无参的简化版

反射的原理及应用_第5张图片


public class A {
    /**
     * 构造方法与实例
     *
     * @param args
     */
    public static void main(String[] args) {
        //无参构造 , 并实例化

        //1 获得 Class
        try {
            // 获得无参的简化版
            SpecificationOption specificationOption = SpecificationOption.class.newInstance();
            System.out.println(specificationOption);
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }


    }
}

获取有参构造

反射的原理及应用_第6张图片
反射的原理及应用_第7张图片

public static void main(String[] args) {
        //有参构造 , 并实例化
        //1 获得 Class
        Class beanClass = SpecificationOption.class;
        //2 获得构造 -- 三个字符串形参 -- (Integer.class,String.class,Integer.class)
        Constructor constructor = null;
        try {
            constructor = beanClass.getConstructor(Integer.class, String.class, Integer.class);
            System.out.println("获得构造 -- 三个字符串形参" + constructor);
            //3 实例对象,三个字符串实参
            Object o = constructor.newInstance(2323,"白色", 1);
            System.out.println(o);
        } catch (Exception e) {
            e.printStackTrace();

        }

    }

1.7.5 扩展:私有构造(暴力反射)

  • 修改 Bean 添加私有构造
private Bean(String id) {
this.id = id;
System.out.println("有参构造:" + id);
}
  • getConstructor() 使用该方法将无法获得私有方法,程序运行抛异常
  • 在这里插入图片描述
  • 没有使用 setAccessible(true),将抛异常
  • 在这里插入图片描述
    反射的原理及应用_第8张图片
@Test
public void testPrivateCons() throws Exception{
//私有构造
//1 获得 Class
Class beanClass = Bean.class;
//2 获得构造 -- 两个字符串形参 -- Bean(String id, String className)
// * getConstructor() 将抛异常 java.lang.NoSuchMethodException
// * getDeclaredConstructor 可以获得私有构造
Constructor constructor = beanClass.getDeclaredConstructor(String.class)
//暴力访问
constructor.setAccessible(true);
//3 实例对象,两个字符串实参
Object bean = constructor.newInstance("userId");
System.out.println(bean);

1.8方法与执行

1.8.1public 方法
  • 获得方法并设置
    反射的原理及应用_第9张图片
  //1 获得 Class
        Class clazz = User.class;
        //2 获得实例 ,相当于 Object obj = new Bean();
        Object obj = clazz.newInstance();
        //3 操作 setAge 方法
        // * 格式:getMethod(方法名,形成列表)
        Method setMethod = clazz.getMethod("setAge", Integer.class);

        System.out.println("getMethod(方法名,形成列表)"+setMethod);
        //3.2 执行方法,一个实参
        Object setReturnObj = setMethod.invoke(obj, 12);
        System.out.println("set 方法返回值:" + setReturnObj);

1.8.2私有方法(暴力反射)private

添加私有方法
反射的原理及应用_第10张图片

反射的原理及应用_第11张图片


        //4 操作 getId 方法
        // 4.1 获得方法,没有形参
        Method getMethod = clazz.getMethod("getAge");
        // 4.2 执行方法,没有实参
        Object getReturnObj = getMethod.invoke(obj);
        System.out.println("get 方法返回值:" + getReturnObj);


         //5 暴力反射私有的构造方法
        Method showMethod = clazz.getDeclaredMethod("show");
        System.out.println("暴力反射私有的构造方法show     "+showMethod);
         //暴力访问
        showMethod.setAccessible(true);
          // 4 执行方法,没有实参
        // obj.setMethod(args)     user.setAge(20)
        Object invoke = setMethod.invoke(obj, 20);
        Object result = showMethod.invoke(obj);
        System.out.println("show私有"+result);

1.8.3 main 方法与执行

添加main方法
反射的原理及应用_第12张图片

反射的原理及应用_第13张图片

 //有参构造 , 并实例化
        Class<User> clazz = User.class;
        //2 获得方法 -- main 静态方法 -- public static void main(String[] args)
        Method mainMethod = clazz.getMethod("main", String[].class);
        Object getReturnObj =  mainMethod.invoke(null, (Object)new String[]{"aaa","bbb"});
        System.out.println("main 方法返回值:|||||||||" + getReturnObj);

1.8.4 public 字段的操作

反射的原理及应用_第14张图片


  //5 操作字段,进行赋值,public String  name;
        //5.1 获得的字段,一个形参
        // * 格式:getField(字段名)
        Field descriptionField = clazz.getField("name");
        System.out.println("getField(字段名)     "+descriptionField);

        //5.2 为对象的字段赋值
        descriptionField.set(obj, "喜欢在文字中倾诉");

        //5.3 获取对象的字段值
        Object fieldReturnObj = descriptionField.get(obj);
        System.out.println("description 字段返回值:       "+fieldReturnObj);


1.8.5 private 字段的操作

反射的原理及应用_第15张图片

反射的原理及应用_第16张图片

   //5 操作字段,进行赋值,private String  name;
        //5.1 获得的字段,一个形参
        // * 格式:getDeclaredField(字段名)
        Field descriptionField = clazz.getDeclaredField("name");
        System.out.println("getDeclaredField(字段名)     "+descriptionField);
        //暴力访问
        descriptionField.setAccessible(true);
        //5.2 为对象的字段赋值
        descriptionField.set(obj, "喜欢在文字中倾诉");

        //5.3 获取对象的字段值
        Object fieldReturnObj = descriptionField.get(obj);
        System.out.println("description 字段返回值:       "+fieldReturnObj);

你可能感兴趣的:(Java基础)