简述反射机制

2023-11-18

一,什么是反射

1.1,反射:所谓框架的灵魂

框架:半成品软件,可以在框架的基础上进行软件开发,简化代码。
反射:将类的各个组成部分封装为其他对象,反射机制。

​ 简单来说反射就是在程序运行期间,动态的获取类或者对象中的属性。

​ 什么是动态获取。

​ 反射的原理就是通过类的字节码文件(class文件)反向获取该类或者对象中的属性,既然是通过字节码获取,这就需要JVM的操作了。下面请看API文档的说明:

1655301-20190912151136918-499683725.png

​ 在上图最后一句话中,文档说的很清楚,反射是在加载类时由JVM进行操作。

1.2,动静态编译

  • 静态编译:在编译期就确定类或者方法的属性,有点一次到位的意思。
  • 动态编译:在运行期确定类或者方法的属性,好比什么时候用就什么时候编译。

​ 但是这两种编译方式有什么区别,先说静态编译吧。我想大家都遇到过项目需求频繁变更的情况,可能是更改需求,可能是添加新的需求。对于静态编译,因为这是一次性编译,对于确定的代码是不能更改的,除非下线,更改,测试,再重新上线,显然这是不妥的。

​ 因此就需要动态编译,即在程序运行期间也可以进行相应的操作,一切操作方式都是灵活的,所以说反射对于程序是多么重要。

1.3,优缺点

​ 先来说说反射的优点:

​ 1,可以在程序运行的过程中,操作这些对象。
​ 2,可以解耦,提高程序的可扩展性。

​ 缺点:

​ 1,因为是JVM操作,所以对于性能来说会有所下降。

​ 2,容易对程序源码造成一定的混乱。

1.4,反射图解

1655301-20190912151153866-1286555727.png

​ **注意:同一个字节码文件(*.class)在程序运行过程中,只会被加载一次。**

1.5,反射获取方式

​ 获取Class对象的方式:
​ 1,Class.forName("全类名"):将字节码文件加载进内存,返回class对象
多用于配置文件中,将类名定义在配置文件中,读取文件并加载类。
​ 2,类名.class:通过类名的属性class获取。
多用于参数的构造。
​ 3,对象.getClass():该方法定义在Object中
多用于对象的字节码获取。

public class ReflectDemo {
    public static void main(String[] args) throws ClassNotFoundException {
        // Class.forName("");
        Class c1 = Class.forName("com.api.reflect.User");
        System.out.println(c1);
        // 类名.class
        Class<User> c2 = User.class;
        System.out.println(c2);
        // .getClass
        User user = new User();
        Class c3 = user.getClass();
        System.out.println(c3);

        System.out.println(c1 == c2);
        System.out.println(c1 == c3);
        System.out.println(c2 == c3);
    }
}

​ 运行结果:

1655301-20190912151207936-2044588760.png

​ 分析:

​ 通过以上三种反射方式都可以获得实例对象,同样也证明三个对象是相同的,也就是对象只会被创建一次。

二,反射常用方法

2.1,成员变量

  • public Field getField(String name):获取指定名称的成员变量(public)。
  • public Field[] getFields():获取全部成员变量(public)。
  • public Field getDeclaredField(String name):不考虑修饰符。
  • public Field[] getDeclaredFields():不考虑修饰符。

​ 创建一个User对象。

public class User implements Serializable {

    public String name;

    protected Integer age;

    Integer sex;

    private String phone;
    
    public User() {
    }

    public User(String name, Integer age, Integer sex, String phone) {
        this.name = name;
        this.age = age;
        this.sex = sex;
        this.phone = phone;
    }
    
    private User(String name, Integer age){
        this.name = name;
        this.age = age;
    }

    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public Integer getAge() {
        return age;
    }
    public void setAge(Integer age) {
        this.age = age;
    }
    public Integer getSex() {
        return sex;
    }
    public void setSex(Integer sex) {
        this.sex = sex;
    }
    public String getPhone() {
        return phone;
    }
    public void setPhone(String phone) {
        this.phone = phone;
    }
    @Override
    public String toString() {
        return "User{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", sex=" + sex +
                ", phone='" + phone + '\'' +
                '}';
    }
     public void run() {
        System.out.println("跑步...");
    }

    private void eat(String username) {
        System.out.println(username + "正在吃饭...");
    }
}
public class ReflectDemo2 {
    public static void main(String[] args) throws Exception {
        // 1,通过Class.forName方式获取User对象
        Class aClass = Class.forName("com.api.reflect.User");
        // 获取public修饰的成员变量
        Field[] fields = aClass.getFields();
        for (Field field : fields) {
            System.out.println("1,public修饰的成员变量--->" + field);
        }

        // 2,获取指定成员变量名称
        Field name = aClass.getField("name");
        System.out.println("2,指定成员变量名称--->" + name);

        // 3,获取全部的成员变量,忽略修饰符
        Field[] declaredFields = aClass.getDeclaredFields();
        for (Field declaredField : declaredFields) {
            System.out.println("3,不考虑修饰符,获取全部成员变量--->" + declaredField);
        }
        // 4,获取指定成员变量
        Field phone = aClass.getDeclaredField("phone");
        // 获取访问权限,暴力反射
        phone.setAccessible(true);
        System.out.println("4,暴力反射--->" + phone);
    }
}

​ 以上代码运行结果:

1655301-20190912151226944-422881028.png

2.2,构造方法

  • public Constructor<T> getConstructor(Class<?>... parameterTypes)
  • public Constructor<?>[] getConstructors()
  • public Constructor<T> getDeclaredConstructor(Class<?>... parameterTypes)
  • public Constructor<?>[] getDeclaredConstructors()
public class ReflectDemo3 {
    public static void main(String[] args) throws Exception {
        // 通过Class.forName方式获取User对象
        Class aClass = Class.forName("com.api.reflect.User");
        // 1,获取指定构造方法(public),参数是可变参数
        Constructor constructor = aClass.getConstructor(String.class, Integer.class, Integer.class, String.class);
        // 实例化对象
        Object user = constructor.newInstance("张三", 20, 1, "123456");
        System.out.println(user);

        // 2,获取全部构造方法(public)
        Constructor[] constructors = aClass.getConstructors();
        for (Constructor constructor1 : constructors) {
            System.out.println(constructor1);
        }

        // 3,不考虑修饰符,获取指定构造方法
        Constructor declaredConstructor = aClass.getDeclaredConstructor(String.class, Integer.class);
        // 获取权限
        declaredConstructor.setAccessible(true);
        Object declaredUser = declaredConstructor.newInstance("李四", 21);
        System.out.println("不考虑修饰符--->" + declaredUser);

        // 4,获取全部构造方法
        Constructor[] declaredConstructors = aClass.getDeclaredConstructors();
        for (Constructor declaredConstructor1 : declaredConstructors) {
            System.out.println("不考虑修饰符--->" + declaredConstructor1);
        }
    }
}

​ 以上代码运行结果:

1655301-20190912151245315-2018927572.png

2.3,成员方法

  • public Method getMethod(String name,Class<?>... parameterTypes)
  • public Method[] getMethods()
  • public Method getDeclaredMethod(String name,Class<?>... parameterTypes)
  • public Method[] getDeclaredMethods()
public class ReflectMethod {
    public static void main(String[] args) throws Exception {
        // 通过Class.forName方式获取User对象
        Class aClass = Class.forName("com.api.reflect.User");
        // 1,获取指定成员方法,public修饰
        Method methodRun = aClass.getMethod("run");
        // 实例化User,并调用invoke()执行方法
        Object user = aClass.newInstance();
        methodRun.invoke(user);
        // 2,获取全部成员方法,public修饰
        Method[] methods = aClass.getMethods();
        for (Method method : methods) {
            System.out.println(method);
        }
        // 3,获取私有成员方法
        Method eat = aClass.getDeclaredMethod("eat", String.class);
        // 获取权限
        eat.setAccessible(true);
        // 执行方法
        eat.invoke(user,"小李");
    }
}

​ 执行结果为:

1655301-20190912151300314-1468179457.png

​ 也许你有疑惑,哪里来这么多的方法。

​ 请详细看除了User对对象中的属性构造方法外,还有Object类中的方法。如下:

1655301-20190912151311572-1093324255.png

这是为什么,请看API文档解释说明:

1655301-20190912151323689-1241274988.png

包括那些由该类或接口声明的以及从超类和超接口继承的那些的类或接口。

Method[] declaredMethods = c1.getDeclaredMethods();
        for (Method declaredMethod : declaredMethods) {
            System.out.println(declaredMethod);
        }

1655301-20190912151334319-907112770.png

三,总结

​ 关于反射中的常用方法就总结到此,反射的用处还是很多的,比如Spring中IOC,DI都是利用反射机制实现的,当然这些会在另一篇博客中总结出来。

​ 以上内容均是自主总结,如有不适之处欢迎留言指正。

感谢阅读!

转载于:https://www.cnblogs.com/fenjyang/p/11512045.html

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

简述反射机制 的相关文章

随机推荐

  • office2021安装教程

    需要用到的工具 office tool plus https otp landian vip zh cn 进到官网点立即下载 下载 包含框架 推荐 下载好解压 运行officetool plus 选择部署 在这里可以看到电脑已存在的offi
  • Spring依赖注入

    一 什么是依赖注入 DI Dependency Injection 依赖注入是指在 Spring IOC 容器创建对象的过程中 将所依赖的对象通过配置进行注入 我们可以通过依赖注入的方式来降低对象间的耦合度 在软件工程中 对象之间的耦合度就
  • 三维重建-opencv实现sfm

    注意 本文中的代码必须使用OpenCV3 0或以上版本进行编译 因为很多函数是3 0以后才加入的 目录 SfM介绍 小孔相机模型 坐标系 内参矩阵 外参矩阵 相机的标定 SfM介绍 SfM的全称为Structure from Motion
  • Java 利用hutool工具实现导出excel并合并单元格

    Java 利用hutool工具实现导出excel并合并单元格 controller层调用service 就一个核心方法 没错就下面这个代码就能实现了 前提是项目里面要引用hutool包 把我这个复制到项目里面然后改掉字段应该能直接跑起来的
  • SQL Server统计数据库表空间大小和数据量

    SQL Server统计数据库表空间大小和数据量 在大数据环境中 对于SQL Server数据库的管理和优化是非常重要的 其中一个关键任务是统计数据库中各个表的空间大小和数据量 通过了解每个表所占用的存储空间 可以进行容量规划 性能优化和资
  • 虚拟机上的Ubuntu开机显示“无法应用原保存的显示器配置”

    如图 解决方法 删除monitors xml 文件 rm config monitors xml
  • pdf模板,java替换变量

    开发十年 就只剩下这套Java开发体系了 gt gt gt 1 创建pdf 现在word中创建模板 输出为pdf文件2 pdf 2 java项目引入依赖
  • 单片机时间戳转换

    看了网上的例程 大多繁琐 直接利用time h里的库函数进行转换即可 include
  • windows上传文件到ubuntu

    进入putty目录下 运行pscp 然后pscp 目标文件 Linux用户名 IP地址 目标文件夹 输入linux的登陆密码即可 more than one remote source not supported 出现这种情况是由空格导致的
  • Linux内核的编译、安装、调试

    这里写目录标题 编译安装内核 下载内核 安装依赖 更改 config 编译内核 安装 首先安装模块 安装内核 更改引导 更改 grub 重启 其他操作 清理内核源目录 卸载安装的内核 修改内核配置菜单实现对新加入内核源码的控制 常见问题 1
  • 8-13外部排序-败者树

    败者树是树形选择排序的一种变体 可视为一棵完全二叉树 通过败者树 可以在k个归并段中选出最小关键字所需要的关键字对比次数更少 绿色为叶子结点 存放初始数据 黑色为失败结点 蓝色为胜出结点 一 基本过程 以下按从小到大的方式构建 1 从8个归
  • Nor Flash,Nand Flash

    文章目录 1 Nor Flash 使用场景 2 Nand Flash 使用场景 3 读写速度对比 4 成本与容量 1 Nor Flash 使用场景 对于大多数应用较为简单的场景 比如 MCU 其内置的 Flash 就是使用的是 Nor Fl
  • python基础开发篇3——线上环境部署Django项目

    文章目录 一 基本了解 二 打包本地项目 三 服务器环境准备 四 安装web服务 4 1 使用uwsgi代理 4 2 使用nginx代理 推荐 五 部署daphne 一 基本了解 部署思路 Nginx服务接收浏览器的动态请求 再通过uwsg
  • 前端上传图片,Python后端接收

    前端代码 h1 Image Upload h1
  • 题目:洛谷1088 火星人(排列组合问题)

    题目描述 人类终于登上了火星的土地并且见到了神秘的火星人 人类和火星人都无法理解对方的语言 但是我们的科学家发明了一种用数字交流的方法 这种交流方法是这样的 首先 火星人把一个非常大的数字告诉人类科学家 科学家破解这个数字的含义后 再把一个
  • homework03

    1 编写一个程序来读入不指定个数的整数 然后决定已经读取的整数中有多少个正数和多少个负数 并计算这些输入值 不统计0 的总和 最终得出它们的平均值 这个程序以输入值0来结束 使用浮点数显示这个平均值 a 0 b 0 sum 0 count
  • Python之ML--机器学习分类算法

    Python之ML 机器学习分类算法 介绍最早以算法方式描述的分类机器学习算法 感知器 perceptron 和自适应线性神经元 adaptive linear neuron 我们将使用python循序渐进地实现一个感知器 并且通过训练使其
  • VSCode与PyCharm提示unresolved import解决方案

    问题描述 在VScode或者pyharm中采用python import自定义模块是 有时会显示unresolved import警告并且 无法跳转到自定义模块函数定义 出现问题的原因 没有安装import对应的模块 import的文件夹没
  • 使用STM32的TIMER进行外部计数

    使用ETR引脚的输入信号作为计数时钟 本例程使用Timer 2 其ETR输入引脚为PA1 该引脚工作模式为输 入模式 Timer的工作模式为从模式 另外使用PC6输出一模拟方波时钟信号 测试时将PC6与PA1短接 用户也可另外连接一个时钟信
  • 简述反射机制

    一 什么是反射 1 1 反射 所谓框架的灵魂 框架 半成品软件 可以在框架的基础上进行软件开发 简化代码 反射 将类的各个组成部分封装为其他对象 反射机制 简单来说反射就是在程序运行期间 动态的获取类或者对象中的属性 什么是动态获取 反射的