反射专题笔记

一、反射机制问题(引出反射)

问题:根据配置文件re.properties指定信息,创建cat对象并调用方法

1-1 前期准备工作

1-1-1 创建配置文件re.properties:

classfullpath=com.java.Cat
method=hi

1-1-2 创建Cat类

public class Cat {
   //私有及共有成员变量
   private String name = "招财猫";
   public int age = 10;
   //含参及无参构造
   public Cat() {}
   public Cat(String name){
       this.name=name;
   }
   //成员方法
   public void hi(){
       //System.out.println("hi" + name);
   }
   public void cry(){
       System.out.println(name + "喵喵叫..."  );
   }
}

1-2 传统方式解决

1-2-1 方法一:创建对象直接调用

Cat cat = new Cat();
cat.hi();

1-2-2 方法二:通过读取流读取配置文件

//2、通过读取流获取路径名和方法名
      //创建配置文件对象
      Properties properties = new Properties();
      //根据路径加载读取配置文件
      properties.load(new FileInputStream("src\\re.properties"));
      //获取配置文件中的路径名
      String classfullpath = properties.get("classfullpath").toString();
      //获取配置文件中的方法名
      String methodName = properties.get("method").toString();
      System.out.println("classfullpath:" + classfullpath); com.java.Cat
      System.out.println("method:" + methodName);// hi

出现了一个问题,就是不能调用其中的方法,只能读取配置文件,要想调用方法,就必须修改源码创建对象。
由此引出反射,解决在不修改源码,只通过修改配置文件实现控制程序,即OCP原则.

二、反射入门案例

//通过反射调用其中方法
//1、通过类路径获取class类
      Class cls = Class.forName(classfullpath);
//2、创建class类对象
      Object o = cls.newInstance();
      System.out.println(o.getClass());//class com.java.Cat
      //可以在不知道配置文件方法名的情况下获取方法对象
      Method method1 = cls.getMethod(methodName);
      //通过方法对象method1传入class对象调用方法,实现在不修改源码的情况下调用不同方法
      //只需修改配置文件中的method=...便可调用不同方法
      method1.invoke(o);//调用方法   传统方法:o.method1 

当我修改re.properties配置文件内的method=cry,会调用Cat中的cry方法
这样就实现了在不修改源代码的情况下,只修改配置文件控制程序

!! 三、反射机制

3-1 原理图

3-2 解释原理图

计算机运行有 编译、加载、运行三个阶段

  • 编译:指java编译生成字节码class文件的过程
  • 加载:通过编译生成的class字节码文件类通过类加载器加载出class类对象,这个过程也体现了反射,也因此Cat.class字节码文件和class类对象是一一对应的关系
  • 运行:当编译与加载完成后的运行阶段
  • 过程理解:当new的时候,会先执行编译阶段,产生Cat.class字节码文件,后通过类的加载器通过反射创建出类的对象,这个时候原字节码文件的成员变量,成员方法,构造方法等都会变成对象,以对应的数组类型存储,字节码文件和class对象是一一映射关系。加载完类对象后,我们可以通过创建Class对象(class.forname("类的全路径")),去实现创建对象,调用方法等功能。同时class类对象和cat对象之间也是一一映射关系,new再多Cat对象也只有一个class类对象

3-3 反射机制作用:

  • 判断一个对象所属的类
  • 运行时创建类的对象
  • 得到或调用类的成员变量和方法
  • 生成动态代理

3-4 反射相关类

四、反射的优缺点及调优

4-1 优缺点:

4-2 应用实例:反射调优

/**
 * 测试反射调用性能,优化方案
 */
public class Reflection02 {
    public static void main(String[] args) throws Exception {
        m1();
        m2();
        m3();
    }
    //一、传统方法调用
    public static void m1() {
        Cat cat = new Cat();
        long start =System.currentTimeMillis();
        for ( int i = 0; i < 900000000; i++) {
            cat.hi();
        }
        long end =System.currentTimeMillis();
        System.out.println("传统方法调用时间=" + (end-start) );
    }

    //二、反射方法调用
    public static void m2() throws Exception {
        //1、获取类对象  三种方式
        Class cls = Class.forName("com.hspedu.Cat");
        //2、创建类对象
        Object o = cls.newInstance();
        //3、创建类对象中的方法对象
        Method method = cls.getMethod("hi");
        long start =System.currentTimeMillis();
        for (int i = 0; i < 900000000; i++) {
            method.invoke(o);//4、通过方法对象去调用方法,需要传入类对象
        }
        long end =System.currentTimeMillis();
        System.out.println("反射方法调用时间=" + (end-start) );
    }

    //三、反射调优 +关闭检查访问 小优化优化的不是很多
    public static void m3() throws Exception {
        //1、获取类对象  三种方式
        Class cls = Class.forName("com.hspedu.Cat");
        //2、创建类对象
        Object o = cls.newInstance();
        //3、创建类对象中的方法对象
        Method method = cls.getMethod("hi");
        method.setAccessible(true);//在反射调用方法时,取消访问检查
        long start =System.currentTimeMillis();
        for (int i = 0; i < 900000000; i++) {
            method.invoke(o);//4、通过方法对象去调用方法,需要传入类对象
        }
        long end =System.currentTimeMillis();
        System.out.println("优化后反射方法调用时间=" + (end-start) );
    }
}

运行结果:

Class类

Class分析

哪些类型有Class对象

Class常用方法

获取Class对象

类加载

反射获取类的结构信息

学习资料来源地址:

https://www.bilibili.com/video/BV1g84y1F7df?p=5&spm_id_from=pageDriver

posted @ 2021-09-08 23:58  赖伯  阅读(46)  评论(0)    收藏  举报