46 反射

作者: ca8519be679b | 来源:发表于2020-05-20 16:40 被阅读0次

    反射,被称为框架设计的灵魂。

    框架:半成品的软件,开发效率高,可以简化代码

    概念:将类的各组成部分封装成其他对象,这就是反射机制

    1

    我们知道java代码在计算机中有三个阶段,如上图,第一阶段源代码阶段,。java代码写好后javac运行编译成字节码.class文件,这时代码是在计算机硬盘中,第三阶段是我们熟悉的运行阶段,创建对象,new之后调用属性方法,而第二阶段是将硬盘文件读取到内存中,是通过java的ClassLoader傀儡实现加载,将成员变量封装成Field,然后多成员变量即使用数组,构造方法封装成Constructor,成员方法封装成Method,其实这就是一种反射机制

    反射的优点,可以在程序运行时调用对象,可以解耦,增加模块扩展性

    为了获取类对象有3种方式:

    1编译阶段,未加载到内存时,Class.forName("类名")将类加载到内存

    2已经在内存中,使用 类名.class获取类对象

    3运行阶段,有new出来的实例,使用实例.getClass()获取类对象,此方法继承自Object

    2

    如上,我们分别使用了3种方法实现获取类对象,其中因为forName方法要抛出异常,我们直接使用了基类Exception,类名字符串必须是包名拼接,我们可以看到3种方法输出一样,同时==来比较这些类对象是否是同一个对象,可以得出结论,class在程序当次运行时只会加载一次(其实Class默认还有泛型,但是我们右侧是指定类型,所以左侧可以省略)

    三种方法,Class.forName方法多用于配置文件,读取文件,加载类

    第二种用于传参,第三种只是利用对象获取字节码class

    Class对象的各种获取方法

    3

    我们获得了字节码对象后,如之前讲的,可以通过各种方法获取成员变量,构造方法,成员方法,还有类名,对应还有获取所有和获取单个的,还有获取一般和Declared的,这个后面讲讲Declared是干嘛用的,我们功能分别讲解

    获取Field成员变量

    4

    还是针对上次使用的Person类,我们定义了无参和有参的构造,getter和setter,还设置了toString方法

    Field[] getFields()方法

    5

    如上,获取类就用Person.class,我们遍历Fields数组,打印发现什么都没有,所以getFields[]返回的其实是public属性

    6

    如上,我们添加几个公有的public属性,可以被打印出来

    7

    为了进一步确定,我们添加默认和protected属性,结果一致

    Field getField(String name)方法  根据指定public属性名获取Field方法

    8

    如上,我们定义了a为public属性,那么就可以获取,如上可以打印出来,但是我们获取到Field对象有什么用呢,

    9

    我们查看文档可以看到Field成员方法,get和set方法,get获取属性值,set给属性设置值,因此我们获取到对象和类就可以给其设置值

    10

    代码如上,为了给参数传入obj,我们实例对象p,a属性默认是int为0,我们设置值后变成33

    Field[] getDeclaredFields()方法

    11

    我们运行可以发现,所有成员变量都打印了出来,不论是public,protected,默认,private

    Field getDeclaredField()方法

    同样,你会认为其是获得不受限的成员属性,其实访问private时报错

    12

    如上,因为私有属性本身还是有保护性的,但是也不是不能访问到

    13

    我们这里需要使用暴力反射Field对象的setAccessible(Boolean)方法,设置为true,我们就可以访问

    获取Constructor构造方法

    14

    如上,我们使用getConstructor方法获取Constructor构造器对象,我们可以指定无参或者有参,有参数的时候,需要使用对应类型的class对象,我们获取到Constructor构造器对象,需要关注的方法就是其newInstance方法,创建实例,我们可以将其打印查看结果

    15

    当然,视频里还说无参情况下可以直接使用class对象的newInstance方法,但是IDE给标横线证明是废弃了,至于获取构造器的其他3个方法,很少用,如果有私有的构造方法,我们记得要使用setAccessible来解决调用问题

    获取Method成员方法

    16

    我们先运行class的getMethods(),可以遍历看到打印的是所有的public方法,包括继承自父类Object的方法

    17

    我们给Person添加2个eat方法,一个无参,一个传入字符串

    18

    使用getMethod,可以指定对象名,我们尝试打印这个Method对象如上

    当然,我们获得Method成员方法,是希望能运行,而不只是打印函数名Method对象,有方法invoke(Object obj,...参数列表)

    19

    如上,我们就分别实现了调用对象的2个eat方法

    当然Method对象还有getName获得方法名

    反射案例

    我们写了很多反射相关的,感觉有的是很墨迹,没有体验到其优秀之处,这里一个案例展示(是黑马视频的案例,要求根据用户配置好的文件,实现创建配置文件指定类,并使用其方法,视频里会说虽然我们现在有Person类,但是还可能有Student类啊,还可能有其他方法啊巴拉巴拉。。)

    20

    视频里介绍配置文件使用.properties后缀存,为什么呢,后续讲,里面写上我们配置的类名和方法名,=连接右侧无引号,如上即编写完毕,其中类名要加上包名

    21

    如上,需要注意的是使用Properties类,可以使用load方法,加载结果存储类似map结构,要求传入的是inputStream,我们可以实例输入流,但是其实我们有类加载器,使用类加载器可以使用其getResourceAsStream获得,pro对象load就可以使用getProperty获得=右侧值,我们就获得了类名和方法名,其他调用就没什么说的了(我们查看框架的配置文件,有时候看见类名,就可以知道使用的是反射机制)

    相关文章

      网友评论

          本文标题:46 反射

          本文链接:https://www.haomeiwen.com/subject/hfgyohtx.html