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


反射机制:
    需求:从【外部】配置文件中获取 类名和方法名 将其运行-》只有反射可以实现
    在不修改源码的情况下控制程序-》设计模式的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 执行方法
        

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
该资源内项目源码是个人的课程设计、毕业设计,代码都测试ok,都是运行成功后才上传资源,答辩评审平均分达到96分,放心下载使用! ## 项目备注 1、该资源内项目代码都经过测试运行成功,功能ok的情况下才上传的,请放心下载使用! 2、本项目适合计算机相关专业(如计科、人工智能、通信工程、自动化、电子信息等)的在校学生、老师或者企业员工下载学习,也适合小白学习进阶,当然也可作为毕设项目、课程设计、作业、项目初期立项演示等。 3、如果基础还行,也可在此代码基础上进行修改,以实现其他功能,也可用于毕设、课设、作业等。 下载后请首先打开README.md文件(如有),仅供学习参考, 切勿用于商业用途。 该资源内项目源码是个人的课程设计,代码都测试ok,都是运行成功后才上传资源,答辩评审平均分达到96分,放心下载使用! ## 项目备注 1、该资源内项目代码都经过测试运行成功,功能ok的情况下才上传的,请放心下载使用! 2、本项目适合计算机相关专业(如计科、人工智能、通信工程、自动化、电子信息等)的在校学生、老师或者企业员工下载学习,也适合小白学习进阶,当然也可作为毕设项目、课程设计、作业、项目初期立项演示等。 3、如果基础还行,也可在此代码基础上进行修改,以实现其他功能,也可用于毕设、课设、作业等。 下载后请首先打开README.md文件(如有),仅供学习参考, 切勿用于商业用途。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值