• day42-反射01


    Java反射01

    1.反射(reflection)机制

    1.1反射机制问题

    一个需求引出反射

    请看下面问题:

    1. 根据配置文件 re.properties 指定信息,创建Cat对象并调用方法hi
    classfullpath=li.reflection.Cat
    method=hi

    使用现有的技术,你能做的到吗?

    1. 这样的需求在学习框架时特别多,即通过外部文件配置,在不修改源码的情况下来控制程序,也符合设计模式的ocp原则(开闭原则)

      开闭原则:不修改源码,扩展功能

    例子:

    re.properties:

    classfullpath=li.reflection.Cat
    method=cry

    Cat:

    package li.reflection;
    public class Cat {
    private String name = "招财猫";
    public void hi() {
    System.out.println("hi " + name);
    }
    public void cry() {
    System.out.println(name + " cry");
    }
    }

    ReflectionQuestion:

    package li.reflection;
    import java.io.FileInputStream;
    import java.io.IOException;
    import java.lang.reflect.InvocationTargetException;
    import java.lang.reflect.Method;
    import java.util.Properties;
    public class ReflectionQuestion {
    public static void main(String[] args) throws IOException, ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchMethodException, InvocationTargetException {
    //根据配置文件 re.properties 指定信息,创建Cat对象 并调用方法hi
    //1.传统方法 new 对象 -->调用方法
    //Cat cat = new Cat();
    //cat.hi();
    //2.尝试使用读取文件的方法
    //2.1使用properties类,可以读写配置文件
    Properties properties = new Properties();
    properties.load(new FileInputStream("src\\re.properties"));
    String classfullpatch = properties.get("classfullpath").toString();
    String methodName = properties.get("method").toString();
    System.out.println("classfullpath" + classfullpatch);
    System.out.println("method" + methodName);
    //2.2创建对象
    //使用传统的方法行不通
    //3.使用反射机制解决
    //3.1加载类,返回一个Class类型的对象cls(这里的Class就是一个类,他的类名就叫Class)
    Class cls = Class.forName(classfullpatch);
    //3.2通过cls得到加载的类 li.reflection.Cat 的一个对象实例
    Object o = cls.newInstance();
    System.out.println("o的运行类型=" + o.getClass());//o的运行类型
    //3.3通过 cls 得你加载的类 li.reflection.Cat 的methodName"hi" 的方法对象
    // 即:在反射机制中,可以把方法视为一个对象(万物皆对象)
    Method method1 = cls.getMethod(methodName);
    //3.4通过 method1 调用方法:即通过方法对象来实现调用方法
    System.out.println("========");
    method1.invoke(o);//传统方法: 对象.方法() , 反射机制:方法.invoke(对象)
    //意义在与反射机制可以通过不求该源码就完成功能的拓展
    /**
    * 例如,在Cat类中有两个方法,hi()和cry(),现在要求将调用用的hi方法改为调用cry方法,
    * 这时候只需要在配置文件re.properties中修改引用的方法名即可
    * 不需像想传统方法一样,需要在源码中修改
    */
    }
    }
    image-20220926160603213

    1.2反射机制

    1.2.1Java Reflection

    1. 反射机制允许程序在执行期间借助于Reflection API取得任何类的内部信息(比如成员变量,构造器,成员方法等等,包括private权限的属性和方法),并能够操作对象的属性以及方法。

      反射在设计模式和框架底层都会用到

    2. 加载完类之后,在堆中就产生了一个Class类型的对象(一个类只有一个Class对象),这个对象包含了类的完整结构信息。通过这个对象得到类的结构。这个Class对象就像一面镜子,透过这个镜子看到了的结构,所以形象地称之为:反射

    例如:一个Person类型的实例对象叫 p

    则 p 对象 - -> 类型 Person类

    Class 对象 cls --> 类型 Class 类(这个类的名字就叫Class)

    1.2.2Java反射机制原理图

    • Java反射机制可以完成
      1. 在运行时判断任意一个对象所属的类
      2. 在运行时构造任意一个类的对象
      3. 在运行时得到任意一个类所具有的成员变量和方法
      4. 在运行时调用任意一个对象的成员变量和方法
      5. 在运行时获取泛型信息
      6. 在运行时处理注解
      7. 生成动态代理

    1.2.3反射相关类

    反射相关的主要类:

    1. java.lang.Class:代表一个类,Class的对象表示某个类加载过后在堆中的对象
    2. java.lang.reflect.Method:表示类的方法(Method对象表示某个类的方法)
    3. java.lang.reflect.Field:表示类的成员变量(Field对象表示某个类的成员变量)
    4. java.lang.reflect.Constructor:表示类的构造方法(Constructor对象表示某个类的构造器)

    ​ 这些类在 java.lang.reflect

    例子:

    Cat:

    package li.reflection;
    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 + " cry");
    }
    }

    re.properties:

    classfullpath=li.reflection.Cat
    method=hi

    Reflection01:

    package li.reflection;
    import java.io.FileInputStream;
    import java.lang.reflect.Constructor;
    import java.lang.reflect.Field;
    import java.lang.reflect.Method;
    import java.util.Properties;
    public class Reflection01 {
    public static void main(String[] args) throws Exception {
    //使用properties类,读写配置文件
    Properties properties = new Properties();
    properties.load(new FileInputStream("src\\re.properties"));
    String classfullpatch = properties.get("classfullpath").toString();
    String methodName = properties.get("method").toString();
    System.out.println("classfullpath" + classfullpatch);
    System.out.println("method" + methodName);
    //反射机制
    //1.加载类,返回一个Class类型的对象cls(这里的Class就是一个类,他的类名就叫Class)
    Class cls = Class.forName(classfullpatch);
    //通过cls得到加载的类 li.reflection.Cat 的一个对象实例
    Object o = cls.newInstance();
    System.out.println("o的运行类型=" + o.getClass());//o的运行类型
    //2.通过 cls得到加载的类 li.reflection.Cat 的methodName"hi" 的方法对象
    // 即:在反射机制中,可以把方法视为一个对象(万物皆对象)
    Method method1 = cls.getMethod(methodName);
    //通过 method1 调用方法:即通过方法对象来实现调用方法
    System.out.println("========");
    method1.invoke(o);//传统方法: 对象.方法() , 反射机制:方法.invoke(对象)
    //3.java.lang.reflect.Field:表示类的成员变量(Field对象表示某个类的成员变量)
    //得到name字段
    //getField不能得到私有的属性
    Field nameField = cls.getField("age");
    System.out.println(nameField.get(o));//传统方法:对象.成员变量 , 反射:成员变量的对象.get(对象)
    //4.java.lang.reflect.Constructor:表示类的构造方法(Constructor对象表示某个类的构造器)
    Constructor constructor1 = cls.getConstructor();//()中可以指定构造器的类型,这里返回无参构造器
    System.out.println(constructor1);//Cat()
    Constructor constructor2 = cls.getConstructor(String.class);//这里传入的String.class 就是String类的Class对象
    System.out.println(constructor2);//Cat(String name)
    }
    }
    image-20220926182012748

    1.2.4反射优点和缺点

    1. 优点:可以动态地创建和使用对象(也是底层框架的核心),使用灵活,没有反射机制,框架技术就失去底层支撑。
    2. 缺点:使用反射机制基本是解释执行,对执行速度有影响
    • 调用反射优化-关闭访问检查
    1. Method和Field、Constructor对象都有setAccessible()方法
    2. setAccessible作用是启动和禁用服务安全检查的开关
    3. 参数值为true表示 反射的对象在使用时 取消访问检查,提高反射效率。参数值为false则表示反射的对象执行访问检查
    image-20220926185959702

    例子:测试反射调用的性能 和优化方案

    package li.reflection;
    import java.lang.reflect.Method;
    //测试反射调用的性能 和 优化方案
    public class Reflection02 {
    public static void main(String[] args) throws Exception {
    m1();
    m2();
    m3();
    }
    //传统方法,调用hi
    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("m1() 耗时=" + (end - start));
    }
    //反射机制调用hi
    public static void m2() throws Exception {
    //拿到Cat类的Class对象
    Class cls = Class.forName("li.reflection.Cat");//这里为了方便,就不读文件了
    //构造Cat类的对象
    Object o = cls.newInstance();
    //得到Cat类的成员方法
    Method hi = cls.getMethod("hi");
    long start = System.currentTimeMillis();
    for (int i = 0; i < 900000000; i++) {
    hi.invoke(o);//反射机制调用方法
    }
    long end = System.currentTimeMillis();
    System.out.println("m2() 耗时=" + (end - start));
    }
    //反射调用优化
    public static void m3() throws Exception {
    //拿到Cat类的Class对象
    Class cls = Class.forName("li.reflection.Cat");//这里为了方便,就不读文件了
    //构造Cat类的对象
    Object o = cls.newInstance();
    //得到Cat类的成员方法
    Method hi = cls.getMethod("hi");
    hi.setAccessible(true);//在反射调用方法时,取消访问检查
    long start = System.currentTimeMillis();
    for (int i = 0; i < 900000000; i++) {
    hi.invoke(o);//反射机制调用方法
    }
    long end = System.currentTimeMillis();
    System.out.println("m3()反射调用优化耗时=" + (end - start));
    }
    }
    image-20220926185830340
  • 相关阅读:
    pdf也可以制作成可翻页的电子书吗?
    算法题目中图和树的存储
    1分钟搞定跨境支付!什么GPT,Calude2不在话下!
    策略模式在springboot中的使用
    五分钟搭建ftp服务器,真的不含糊
    创新之力迸发无限想象,联想创新开放日触见未来科技
    C++11特性-自动类型推导
    iClient for Leaflet实现动态绘圆的几何查询
    以科技传递温度,vivo亮相数字中国建设峰会
    【HarmonyOS NEXT】鸿蒙customScan (自定义界面扫码)
  • 原文地址:https://www.cnblogs.com/liyuelian/p/16732313.html