反射(理论详细到不能详细,需要不断实践)


反射机制:
    需求:从【外部】配置文件中获取 类名和方法名 将其运行-》只有反射可以实现
    在不修改源码的情况下控制程序-》设计模式的ocp开闭原则
        (开:功能开放给你使用,闭:不让修改源码)
        
    反射解决:
        加载类 Class.forName(path);  返回Class类的对象-》文件中类的 Class原型对象
        获取真正的对象实例  Class原型对象.newInstance() 返回object对象,可以强转
        获取方法            Class原型对象.getMethod(methodString),返回Method对象(将方法当作对象)
        调用方法            方法对象.invoke(真正的对象实例)  通过方法对象+对象实例 调用方法(我调我自己)
                                                        和传统的对象.方法的对象调用方法不同
    牛逼:调用其他方法,传统肯定要修改源码;反射只要修改配置文件就行了
    
    反射机制:    
        让Java在程序运行期间借助Reflect API【获取/操控】 【任何类】的内部信息(成员变量,构造器,成员方法)
        依靠:类加载后,会产生一个唯一的class_mirror(也就是一个类对应一个Class类对象)
            镜子所以叫反射
            Class原型对象没有什么特别,就是包含完整类信息的一个 在堆中的 类加载完,自动创建的对象而已
    
        Java程序阶段
            .java/.class字节码文件   叫 源码阶段
            运行到创建对象语句时        执行类加载阶段,将类加载,并在堆创建Class原型对象
                怎么完成的呢?  通过类加载器ClassLoader实现的,加载类,并生成原型对象
                有什么用:        原型对象内的成员变量等 会映射成为一种数据结构(Field[]对象等)
                通过原型对象生成真正的对象 也是在堆中(【重要】:该对象是能够知道其是属于哪个原型对象的)
                    -》所以可以通过这个真正的对象,拿到Class原型对象的东西
                    -》拿到Class类对象,就可以
                        1 构造任意一个类的对象
                        2 判断任意一个对象所属的类
                        3 得到/调用任意一个类所具有的成员变量和方法
                        4 生成动态代理
                        
  
class类对象:
    原型对象
    Class原型对象没有什么特别,就是包含完整类信息的一个 在堆中的 类加载完,自动创建的对象而已
    
    
    class类也是类,继承object
    class类对象,不是new出来的,是系统创建的(classLoader的loadClass方法)
        传统方法创建对象追源码 可以看到
        或 反射创建对象也能看到  但是不要一起,因为类只能加载一次(下面那个追源码可能看不到)
        看class对象的hashcode()也能看到
    每个类的class类对象,是唯一的,类只加载一次
    每个对象知道其class对象是什么  getClass方法
    类的字节码二进制数据是放在方法区的,有的称为元数据
        元数据是二进制,不利于操作,所以又生成了class类对象
    
    直接打印输出 class原型对象 是输出此原型对象代表的类 的类型
        class原型对象也可以调用getClass()方法  ,打印是 java.lang.Class
    
    Class类常用方法
        静态方法
            forName
        成员方法
            newInstance()
            getPacket()包名
            getName()类名
            getSuperClass()
            getInterfaces()
            getClassLoader()
            getConstructers()
            getMethod()
            getField()
            getDeclaredField()
            getAnnotations()
    
    获取Class类对象的6大方式
        源码阶段                Class.forName(参数) 
        Class类加载阶段         类.class      类加载器加载获取loadClass(参数) 参数是全类名字符串
        运行阶段             对象.getClass()
        
        基本类型数据 通过.class获取Class原型对象 
        包装类型数据 通过.TYPE获取class原型对象
        基本和包装,如果类型相同,获取到的其实是一个对象 hashcode码都相同
    
    Java中哪些类型有Class原型对象
        外部类和四大内部类
        接口
        数组,多维数组
        枚举
        注解
        基本数据类型
        void
        Class
            
    
    


源码阶段 .java/.class字节码文件   叫 源码阶段
类加载阶段 通过类加载器完成类加载,在堆中生成原型对象,生成真正的对象
运行阶段    执行方法等操作

类加载:
    静态加载:编译时加载相关类,没有就报错,依赖性太强(编译时就会验证)
        new对象
        子类加载,父类也加载
        调用类中静态方法
    动态加载:运行时加载相关类,没有运行到这个类,不会加载,运行到,即使不存在也不报错,依赖性不强  
        编译时不会加载这个类,只有执行到 那行代码 才会加载(编译不会验证,延时加载)
        通过反射
    
    类加载过程细节/阶段(不论是静态加载还是动态加载)
        Java编译-javac编译-》class字节码-java运行-》
            加载
                将类的class文件读入到内存,并为其创建java.lang.class对象  过程由类加载器完成
                依赖的是二进制字节流
            连接
                将类的二进制数据合并到JRE中
                验证
                    对文件进行进行安全校验:文件格式,元数据,字节码,符号引用
                    为了保证文件不会损害jvm虚拟机
                    源码:ClassLoader的loadClass内有SecurityManger类
                    -Xverify:none参数来关闭大部分类的验证措施,提升效率
                准备
                    给静态【变量】分配内存并进行【默认】初始化
                解析
                    将常量池中的符号引用(逻辑引用),替换为直接引用(分配地址了,就变成地址引用了)
            初始化
                jvm负责对类进行初始化,初始化静态内容
                执行是<Clint>()方法
                    虚拟机保证此方法,加锁同步,多线程执行类加载同一个类,只会执行一个,其他阻塞,直到执行完一个
                    源码:loadClass方法内可以看到加锁
                注意:这里是类的初始化阶段,不是new,new是对象创建阶段,所以这里是静态内容
                    new执行的是<init>()方法,其中包含成员变量赋值和构造器的
             


反射相关类  【看API】
    Class类
    Method类
    Field类
    Constructor类  获取带参构造器,方法传递参数的原型对象  String.class等
    反射好多都是反着写的    执行方法/获取属性值等    
    
    //使用class对象(字节码对象) 用class类方法
        //    获取(大部分方法)
        //        获取成员变量 们     Field[] getFields()     获取public修饰的所有成员变量
                                int  getModifies()  int形式返回修饰符 默认是0,public是1 static final等
                                getType() 以Class形式返回类型
                                getName() 返回属性名
        //                        Field getField(String name)    获取public修饰的指定名称的成员变量
        //                        Field[] getDeclaredFields() 获取所有成员变量
        //                        Field getDeclaredField(String name)    获取指定名称的成员变量
        //                            后两个不考虑访问权限修饰符 反射面前没有公有私有 都可以设置/获取
        //                            但需要在不是public的操作前,需要忽略访问权限修饰符的安全检查 setAcessible(true)方法 暴力反射
        //            获取后使用: Field类方法 set/get方法 方法传参传一个成员变量所在类 的对象   设置/获取成员变量  成员变量使用:设置/获取
        //        获取构造方法 们        Constructor 同上 传参区分 不同构造方法 传参类似(int.class,int.class)
        //            获取后使用: Constructor类方法newInstance创建类对象,返回值是object类型,要强转为所要类的类型  构造方法使用:创建对象
        //        获取成员方法 们         Method 同上 传参是方法名的字符串形式 与方法参数列表的.class形式(方法名与参数列表确定方法)
        //            获取后使用: Method类方法 invoke(。。。)执行方法 参数是方法所在类 的对象名+方法参数 值    方法返回值默认object可能需要强转
        //                    method.invoke()抛出InvocationTargetException异常:
        //                    原因:如果方法中本来就有异常并且直接抛出了异常(没处理或抛出了),通过反射进行调用时,会抛出InvocationTargetException异常
        //        获取方法名称 们        String getName()    获取到的还包括object类/父类的所有被继承的方法,不止类本身方法
        //    应用:案例:需求:框架前提:不能改变该类任何代码 ;   可以帮完美创建任意类的对象,并可以执行任意方法
        //        实现:1配置文件    2反射
        //        步骤:1 将需要创建的对象的 全类名 和 需要执行的方法 定义在配置文件中
        //            2 在程序中加载读取配置文件  Properties     本类名称. class.getClassLoader方法 获取此目录的 文件加载器
        //                                                返回值是ClassLoader类对象, 类的成员方法getResourceAsStream(“文件名称”)方法返回值是文件字节流
        //                                                注意:这个文件必须直属于src,否则会找不到,抛运行期异常,不能在包pakeage里
        //            3 使用反射技术来加载 类文件 进入内存
        //            4 创建对象
        //            5 执行方法


反射优点与缺点:
    优点:框架灵魂,灵活创建和使用对象
    缺点:使用反射基本是解释执行,对执行速度有影响
        调用方法很多次,测试传统调用,和反射调用差距
        
反射优化:
    Method,Field,Constructor对象都有setAccessible()方法
        设置为true,表示 禁用访问检查,提高执行效率,反射调用方法前设置
    
    
    


反射爆破:setAccessible 爆破  true就是为了访问非public成员
    创建对象
        调用类中的public修饰的无参构造器
        调用类中的指定构造器
        Class类相关方法
            newInstance() 调用的是无参
            getConstructor(clazz class。。)获取相应参数的构造器对象
            getDecalaredConstructor(clazz class。。)获取相应参数的构造器对象
        Constructor类相关方法
            setAccessible 爆破  true
            newInstance(Object..obj)调用构造器
    操作属性
        Class类相关方法
            getDeclaredField(属性名)
        Field类方法
            setAccessible 爆破
            set/get(参数)方法  参数是Field对象,如果上面的属性是static,那么可以写为null,因为静态和对象无关
    操作方法
        Class类相关方法
            newInstance() 调用的是无参
            getDeclaredMethod(方法名,XX。class)  返回Method m
        Method类相关方法
            setAccessible 爆破  true
            m.invoke(对象,实参列表) 静态方法,对象可以写null,返回值是Object类型
            
            
            

反射学习历史
    
        //反射(reflect):将类的各个组成部分封装为其他对象,这就是反射机制
        // 应用 框架设计的灵魂 ,写框架用,用框架一般不用
        // 框架:半成品软件,可以在框架基础上进行软件开发,简化【编码量】 不是代码量
        // Java程序运行的三个阶段:每段Java代码都会经历这三个阶段
        //                第一阶段 Source源代码阶段 【硬盘中】 .Java程序  
        //                    用javac编译 生成 .class文件(包括 成员变量,构造方法,成员方法。。。)
        //                第二阶段 Class类对象阶段 【内存中】 内存中出现一个对象【class类对象】 用来描述.class字节码文件
        //                    成员变量可以封装为Field对象/对象数组 
        //                    构造方法可以封装为Constructor对象/对象数组
        //                    成员方法可以封装为Method对象/对象数组
        //                第三阶段 Runtime运行期阶段 用class类对象,创建真正的Java类对象(如Person对象等),运行代码
        // 反射好处:1在代码运行过程中 ,操作(获取,改变)这些对象
        //          2可以解耦,提高程序的可扩展性
        
        //class类对象获取 三种方式(对应三个阶段) 三个方法的返回值接收没有必要加泛型
        //    1 class类静态方法 Class.forName("全类名") 方法本身有异常。传参的字符串 全类名是 包名+类名
        //            将字节码.class文件 加载进内存 返回class类对象 多用于配置文件,将类名写在配置文件中,读取文件,加载类名
        //            ClassNotFound异常 是包名/类名写错 可以直接复制过来用于解决
        //    2 类名.class 通过类名的属性class来获取  多用于参数传递
        //    3 对象名.getclass() 多用于类对象获取字节码对象 (这个方法封装在object类中,所有对象都会有这个方法)
        //    注意:这三个class类对象输出的 字符串形式一样 
        //        那么  再用==测试为true 内存地址也相同,
        //        说明  三个对象完全相同
        //             同一个字节码文件(*.class)在程序执行过程中,只会被加载一次 不论以哪种方式获取的class对象都是同一个
        
        //使用class对象(字节码对象) 用class类方法
        //    获取(大部分方法)
        //        获取成员变量 们     Field[] getFields()     获取public修饰的所有成员变量
        //                        Field getField(String name)    获取public修饰的指定名称的成员变量
        //                        Field[] getDeclaredFields() 获取所有成员变量
        //                        Field getDeclaredField(String name)    获取指定名称的成员变量
        //                            后两个不考虑访问权限修饰符 反射面前没有公有私有 都可以设置/获取
        //                            但需要在不是public的操作前,需要忽略访问权限修饰符的安全检查 setAcessible(true)方法 暴力反射
        //            获取后使用: Field类方法 set/get方法 方法传参传一个成员变量所在类 的对象   设置/获取成员变量  成员变量使用:设置/获取
        //        获取构造方法 们        Constructor 同上 传参区分 不同构造方法 传参类似(int.class,int.class)
        //            获取后使用: Constructor类方法newInstance创建类对象,返回值是object类型,要强转为所要类的类型  构造方法使用:创建对象
        //        获取成员方法 们         Method 同上 传参是方法名的字符串形式 与方法参数列表的.class形式(方法名与参数列表确定方法)
        //            获取后使用: Method类方法 invoke(。。。)执行方法 参数是方法所在类 的对象名+方法参数 值    方法返回值默认object可能需要强转
        //                    method.invoke()抛出InvocationTargetException异常:
        //                    原因:如果方法中本来就有异常并且直接抛出了异常(没处理或抛出了),通过反射进行调用时,会抛出InvocationTargetException异常
        //        获取方法名称 们        String getName()    获取到的还包括object类/父类的所有被继承的方法,不止类本身方法
        //    应用:案例:需求:框架前提:不能改变该类任何代码 ;   可以帮完美创建任意类的对象,并可以执行任意方法
        //        实现:1配置文件    2反射
        //        步骤:1 将需要创建的对象的 全类名 和 需要执行的方法 定义在配置文件中
        //            2 在程序中加载读取配置文件  Properties     本类名称. class.getClassLoader方法 获取此目录的 文件加载器
        //                                                返回值是ClassLoader类对象, 类的成员方法getResourceAsStream(“文件名称”)方法返回值是文件字节流
        //                                                注意:这个文件必须直属于src,否则会找不到,抛运行期异常,不能在包pakeage里
        //            3 使用反射技术来加载 类文件 进入内存
        //            4 创建对象
        //            5 执行方法
        

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/201722.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

阿里云语雀频繁崩溃,有什么文档管理工具是比较稳定的?

10月23 日14:00左右&#xff0c;蚂蚁集团旗下的在线文档编辑与协同工具语雀发生服务器故障&#xff0c;在线文档和官网都无法打开。直到当天晚上22:24&#xff0c;语雀服务才全部恢复正常。从故障发生到完全恢复正常&#xff0c;语雀整个宕机时间将近 8 小时&#xff0c;如此长…

【SpringCloud篇】Eureka服务的基本配置和操作

文章目录 &#x1f339;简述Eureka&#x1f6f8;搭建Eureka服务⭐操作步骤⭐服务注册⭐服务发现 &#x1f339;简述Eureka Eureka是Netflix开源的一个基于REST的服务治理框架&#xff0c;主要用于实现微服务架构中的服务注册与发现。它由Eureka服务器和Eureka客户端组成&#…

机器学习与 S3 相集成 :释放数据的力量

文章作者&#xff1a;Libai 引言 在当今数据驱动的世界中&#xff0c;企业不断寻求如何高效利用企业自身所产生的数据的解决方案。机器学习已经成为一种提取有价值的见解和做出数据驱动决策的强大工具。然而&#xff0c;机器学习模型的成功在很大程度上依赖于高质量数据的可用…

算能技术资料地址、Demo github地址

技术资料地址&#xff1a; https://developer.sophgo.com/site/index/material/38/all.html Demo github地址&#xff1a;https://github.com/sophgo/sophon-demo

人工智能在警务工作中的运用

AI 能否帮助警察打击犯罪&#xff1f; 执法部门负责维护公共安全&#xff0c;他们必须处理随之而来的所有挑战。幸运的是&#xff0c;警察可以依靠技术来处理很多工作。近几年来&#xff0c;尤其是人工智能技术在全球变成了警务工作中的一个重要部分。 随着基于 AI 的警务技术…

java-poi操作笔记

row表示行&#xff0c;cell表示row中的第几个cell package sample.Utils;import org.apache.poi.hssf.usermodel.HSSFWorkbook; import org.apache.poi.ss.usermodel.Cell; import org.apache.poi.ss.usermodel.DateUtil; import org.apache.poi.ss.usermodel.Workbook; impor…

c++搭建http服务器

HTTP请求协议格式如下&#xff1a; HTTP响应协议格式如下&#xff1a; #include <iostream> #include <winsock2.h> #include <ws2tcpip.h> #include <string>#pragma comment(lib, "ws2_32.lib")//std::string generateResponse(const st…

企业级SQL开发:如何审核发布到生产环境的SQL性能

自从上世纪 70 年代数据库开始普及以来&#xff0c;DBA 们就不停地遭遇各种各样的数据库管理难题&#xff0c;其中最为显著的&#xff0c;可能就是日常的开发任务中&#xff0c;研发人员们对于核心库进行变更带来的一系列风险。由于针对数据库的数据变更是一项非常常见的任务&a…

C#-关于网络

操作IP地址、执行DNS查询。。。 使用套接字编程&#xff1b; 创建TCp和UDP客户端和服务器 使用HttpClient及其工厂&#xff1b;

python文件docx转pdf

centos部署的django项目&#xff0c;使用libreoffice做文件转换&#xff0c;官网给环境安装好libreoffice后&#xff0c;可使用命令行来进行转化 还可转换其他的各种格式&#xff0c;本文只做了pdf转换 import subprocess import os def convert_to_pdf(input_file, o…

Linux修改时区失败,手动修改localtime无效

有时候改了这个也不行&#xff0c;用命令行修改也不行 解决办法 &#xff1a;cp /usr/share/zoneinfo/Asia/Shanghai /etc/localtime 或者想改其他时区的直接 ll /usr/share/zoneinfo/ 查看

DTCC2023大会-基于eBPF观测数据库-附所有PPT下载链接

DTCC2023大会-基于eBPF观测数据库-附所有PPT下载链接 8月16日—18日,第14届中国数据库技术大会(DTCC-2023)在北京国际会议中心举行。聚好看在大会上首次发布基于eBPF观测数据库性能的产品DBdoctor&#xff0c;受到了业界广泛的关注。近期几位业内同仁过来要大会的PPT&#xff…

python爬虫-某公开数据网站实例小记

注意&#xff01;&#xff01;&#xff01;&#xff01;某XX网站逆向实例仅作为学习案例&#xff0c;禁止其他个人以及团体做谋利用途&#xff01;&#xff01;&#xff01; 第一步&#xff1a;分析页面和请求方式 此网站没有技巧的加密&#xff0c;仅是需要携带cookie和请求…

Flask下载文件接口,以excl表哥为例

一、response 1、定义写入表哥的代码 def create_excel_xls(path, sheet_name, value):index len(value) # 获取需要写入数据的行数workbook xlwt.Workbook() # 新建一个工作簿sheet workbook.add_sheet(sheet_name) # 在工作簿中新建一个表格for i in range(0, inde…

使用Redis做数据缓存

目的 本关目的&#xff1a;使用Redis实现数据缓存。 相关知识 本文将将会你掌握&#xff1a;1&#xff0e;将数据加入缓存队列&#xff0c;2&#xff0e;缓存数据。 在我之前的文章中提到了实现了使用 Redis 做动态页面缓存&#xff0c;以此提高访问速度&#xff0c;但同时…

【AntDB 数据库】国产数据库发展之信创政策的加持

由于我国在信息技术领域起步较晚&#xff0c;国内大量的市场份额被国际IT巨头占据&#xff0c;甚至长期处于被垄断的地位&#xff0c;这也给了某些国家妄图通过挑起科技、贸易摩擦制衡我国发展的机会。为了解决可能存在的安全风险&#xff0c;在重要信息系统、关键基础设施中使…

什么牌子的开放式耳机好?开放式耳机选购指南来了!

在当今音频科技不断演进的时代&#xff0c;开放式耳机作为一种受欢迎的音频设备&#xff0c;吸引着越来越多的消费者&#xff0c;与封闭式耳机相比&#xff0c;开放式耳机在音质表现和舒适度上都具有独特的优势&#xff0c;在众多品牌和型号中选择一款满足个人需求的开放式耳机…

L1-022:奇偶分家

题目描述 给定N个正整数&#xff0c;请统计奇数和偶数各有多少个&#xff1f; 输入格式&#xff1a; 输入第一行给出一个正整N&#xff08;≤1000&#xff09;&#xff1b;第2行给出N个非负整数&#xff0c;以空格分隔。 输出格式&#xff1a; 在一行中先后输出奇数的个数、偶数…

劲松中西医结合医院回应:选择HPV医院标准及注意事项

随着目前我国HPV感染人群不断增多&#xff0c;其健康形势不容乐观&#xff0c;因此选择一家好的HPV医院对于恢复健康至关重要。HPV感染人群在选择HPV医院时&#xff0c;往往需要关注多个方面的因素。以下是一些具体建议&#xff0c;在难以抉择时可作为参考&#xff1a; 一、考…

C 语言格式化输出时间

本文部分内容借助于 AI 生成~ struct tm 是C语言标准库 <time.h> 中自带的结构体类型之一。它用于表示日历时间和日期时间的组成部分。 struct tm 结构体定义了以下成员变量&#xff1a; int tm_sec: 秒&#xff08;0-59&#xff09;int tm_min: 分钟&#xff08;0-59…