反射 p1 反射机制

打印 上一主题 下一主题

主题 698|帖子 698|积分 2094

反射机制

引出反射



  • 这样的需求在学习框架时特别多,即通过外部文件配置,在不修改源码的情况下,来控制程序,也符合设计模式的OCP原则(开闭原则:不修改源码,扩展功能)。
  • 代码演示:
    re.properties文件:
    1. classfullpath=com.hspedu.Cat
    2. method=cry
    复制代码
    Cat类:
    1. package com.hspedu;
    2. /**
    3. * @author: 86199
    4. * @date: 2023/5/18 10:09
    5. * @description:
    6. */
    7. public class Cat {
    8.     private Strinag name = "招财猫";
    9.     public int age = 10;
    10.    
    11.     public Cat() {
    12.     }
    13.    
    14.     public Cat(String name) {
    15.         this.name = name;
    16.     }
    17.     public void hi(){
    18.         System.out.println("hi" + name);
    19.     }
    20.     public void cry(){
    21.         System.out.println(name + "喵喵叫");
    22.     }
    23. }
    复制代码
    ReflectionQuestion:
    1. package com.hspedu.reflection.question;
    2. import com.hspedu.Cat;
    3. import java.io.FileNotFoundException;
    4. import java.io.FileReader;
    5. import java.io.IOException;
    6. import java.lang.reflect.InvocationTargetException;
    7. import java.lang.reflect.Method;
    8. import java.util.Properties;
    9. /**
    10. * @author: 86199
    11. * @date: 2023/5/18 10:14
    12. * @description:
    13. */
    14. public class ReflectionQuestion {
    15.     public static void main(String[] args) throws IOException, ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchMethodException, InvocationTargetException {
    16.         //普通方式
    17. //        Cat cat = new Cat();
    18. //        cat.hi();
    19.         //IO流,使用Preperties类读写配置文件
    20.         Properties properties = new Properties();
    21.         properties.load(
    22.                 new FileReader("src\\com\\hspedu\\re.properties"));
    23.         String classfullpath = properties.get("classfullpath").toString();
    24.         String methodName = properties.getProperty("method");
    25.         System.out.println(classfullpath);
    26.         System.out.println(methodName);
    27.         //使用反射解决
    28.         //(1)加载类,返回Class类型的对象 cls
    29.         Class cls = Class.forName(classfullpath);
    30.         //(2)通过cls 得到你的加载的类 com.hspedu.Cat 的对象实例
    31.         Object o = cls.newInstance();
    32.         System.out.println("o 的运行类型 = " + o.getClass());//运行类型
    33.         //(3)通过 cls 得到你加载的类 com.hspedu.Cat 的 methodName"hi" 的方法对象
    34.         //   即:在反射中,可以把方法视为对象(万物皆对象)
    35.         Method method = cls.getMethod(methodName);
    36.         //(4) 通过method调用方法:即通过方法对象类实现调用方法
    37.         System.out.println("============================");
    38.         method.invoke(o);
    39.         //可以直接通过修改配置文件,而不是源码来改变调用的方法
    40.     }
    41. }
    42. /*运行结果:
    43. com.hspedu.Cat
    44. cry
    45. o 的运行类型 = class com.hspedu.Cat
    46. ============================
    47. 招财猫喵喵叫
    48. */
    复制代码
反射机制


  • 反射机制允许程序在执行期间借助于Reflection API取得任何类的内部信息(比如成员变量,构造器,成员方法等等),并能操作对象的属性及方法。反射在设计模式和框架底层都会用到;
  • 加载完类之后,在堆中就产生了一个Class类型的对象(一个类只有一个Class对象),这个对象包含了类的完整结构信息。通过这对象得到类的结构。这个对象就像一面镜子,透过这个镜子看到类的结构,所以形象的称之为:反射。
  • 在启动时,包含main方法的类被加载。它会加载所有需要的类。这些被加载的类又要加载它们需要的类,以此类推。


  • 反射原理图

  • 弹幕摘要:

    • 加载的过程在方法区,加载结果(对象)在堆区,不知道对不对;
    • 类加载是将数据放入的内存的方法区中,然后在堆创建一个class对象,说白了就是堆中的class是用来封装方法区数据的类

  • 疑惑:

    • 那为什么需要这样一个Class对象呢?


      • Class类的对象的作用是运行时提供或获得某个对象的类型信息,这点对于反射技术很重要。
      • 是这样的,当我们new一个新对象或者引用静态成员变量时,Java虚拟机(JVM)中的类加载器子系统会将对应Class对象加载到JVM中,然后JVM再根据这个类型信息相关的Class对象创建我们需要实例对象或者提供静态变量的引用值。也就是说,Class对象对于类的实例化具有非常重要的意义。没它就没法new新对象和引用静态成员变量。
      ————————————————
      版权声明:本文为CSDN博主「一只野生饭卡丘」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
      原文链接:https://blog.csdn.net/Searchin_R/article/details/84591735


反射相关的主要类


  • java.lang.Class:代表一个类,Class对象表示某个类加载后在堆中的对象;
  • java.lang.reflect.Method:代表类的方法,Method对象表示某个类的方法;
  • java.lang.reflect.Field:代表类的成员变量,Field对象表示某个类的成员变量;
  • java.lang.reflect.Constructor:代表类的构造方法,Constructor对象表示构造器;


  • 代码演示
    1. package com.hspedu.reflection;
    2. import java.io.FileReader;
    3. import java.lang.reflect.Constructor;
    4. import java.lang.reflect.Field;
    5. import java.lang.reflect.Method;
    6. import java.util.Properties;
    7. /**
    8. * @author: 86199
    9. * @date: 2023/5/20 10:52
    10. * @description:
    11. */
    12. public class Reflection01 {
    13.     public static void main(String[] args) throws Exception{
    14.         //1. IO流,使用Preperties类读写配置文件
    15.         Properties properties = new Properties();
    16.         properties.load(
    17.                 new FileReader("src\\com\\hspedu\\re.properties"));
    18.         String classfullpath = properties.get("classfullpath").toString();
    19.         String methodName = properties.getProperty("method");
    20.         //2. 使用反射解决
    21.         //(1)加载类,返回Class类型的对象 cls
    22.         Class cls = Class.forName(classfullpath);
    23.         //(2)通过cls 得到你的加载的类 com.hspedu.Cat 的对象实例
    24.         Object o = cls.newInstance();
    25.         System.out.println("o 的运行类型 = " + o.getClass());//运行类型
    26.         //(3)通过 cls 得到你加载的类 com.hspedu.Cat 的 methodName"hi" 的方法对象
    27.         //   即:在反射中,可以把方法视为对象(万物皆对象)
    28.         Method method = cls.getMethod(methodName);
    29.         //(4) 通过method调用方法:即通过方法对象类实现调用方法
    30.         System.out.println("============================");
    31.         method.invoke(o);
    32.         //java.lang.reflect.Field:代表类的成员变量,Filed对象白哦是某个类的成员变量
    33.         //得到age字段
    34.         //getField不能得到私有属性
    35.         Field ageFiled = cls.getField("age");
    36.         System.out.println(ageFiled.get(o));
    37.         //java.lang.reflect.Constructor:代表类的构造方法,Constructor对象表示构造器
    38.         Constructor constructor = cls.getConstructor();//()中可以指定构造器参数类型,不指定返回无参构造器
    39.         System.out.println(constructor);//Cat()
    40.         Constructor constructor1 = cls.getConstructor(String.class);//传入String类的Class对象
    41.         System.out.println(constructor1);//Cat(java.lang.String)
    42.     }
    43. }
    复制代码
  • 反射的优缺点:

    • 优点:可以动态的创建和使用对象(也是框架的底层核心),使用灵活,没有反射机制,框架技术就失去了底层支撑。
    • 缺点:使用反射基本是解释执行,对执行速度有影响。

反射调用优化——关闭访问检查


  • Method和Field、Constructor对象都有setAccessible()方法;
  • setAccessible()作用是启动和禁用访问安全检查的开关;
  • 参数值为true表示反射的对象在使用时取消访问检查,可以提高反射的效率。参数值为false则表示反射的对象执行访问检查。


  • 代码演示:
    1. package com.hspedu.reflection;
    2. import com.hspedu.Cat;
    3. import java.lang.reflect.InvocationTargetException;
    4. import java.lang.reflect.Method;
    5. /**
    6. * @author: 86199
    7. * @date: 2023/5/20 11:20
    8. * @description: 测试反射调用的性能,和优化方案
    9. */
    10. public class Reflection02 {
    11.     public static void main(String[] args) throws ClassNotFoundException, InvocationTargetException, InstantiationException, IllegalAccessException, NoSuchMethodException {
    12.         m1();
    13.         m2();
    14.         m3();
    15.     }
    16.     //这里先把hi()方法中的打印注释了
    17.     //传统方法调用方法hi
    18.     public static void m1(){
    19.         Cat cat = new Cat();
    20.         long start = System.currentTimeMillis();
    21.         for (int i = 0; i < 90000000; i++){
    22.             cat.hi();
    23.         }
    24.         long end = System.currentTimeMillis();
    25.         System.out.println("m1() 耗时 = " + (end - start));
    26.     }
    27.     //反射机制调用方法hi
    28.     public static void m2() throws ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchMethodException, InvocationTargetException {
    29.         Class cls = Class.forName("com.hspedu.Cat");
    30.         Object o = cls.newInstance();
    31.         Method method = cls.getMethod("hi");
    32.         long start = System.currentTimeMillis();
    33.         for (int i = 0; i < 90000000; i++){
    34.             method.invoke(o);
    35.         }
    36.         long end = System.currentTimeMillis();
    37.         System.out.println("m2() 耗时 = " + (end - start));
    38.     }
    39.     //反射优化:关闭访问检测
    40.     public static void m3() throws ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchMethodException, InvocationTargetException {
    41.         Class cls = Class.forName("com.hspedu.Cat");
    42.         Object o = cls.newInstance();
    43.         Method method = cls.getMethod("hi");
    44.         method.setAccessible(true);//取消在访问调用方法时的访问检查
    45.         long start = System.currentTimeMillis();
    46.         for (int i = 0; i < 90000000; i++){
    47.             method.invoke(o);
    48.         }
    49.         long end = System.currentTimeMillis();
    50.         System.out.println("m3() 耗时 = " + (end - start));
    51.     }
    52. }
    53. /*运行结果
    54. m1() 耗时 = 3
    55. m2() 耗时 = 197
    56. m3() 耗时 = 168
    57. */
    复制代码

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

勿忘初心做自己

金牌会员
这个人很懒什么都没写!

标签云

快速回复 返回顶部 返回列表