Java反射机制之反射构建对象以及给属性赋值

        总结一下今天所学,我们在学习java的时候,总会多多少少的听到过反射机制,但是我们好像听过之后就过去了,从来没去了解过它,然后平时做东西,也没有用到过。久而久之就慢慢给淡忘了。有时候面试的时候会被问道,你既然是学java的,你知道反射吗?你来说说反射吧,然后脑子一懵,自己好像对反射的了解好像就只有反射这两个字而已。本篇文章,我们就来聊一聊java中的反射机制。

什么是反射?

        首先,我们要知道什么是反射。先来一个百度百科上的官方解释:
        JAVA反射机制是在运行状态中,对于任意一个实体类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意方法和属性;这种动态获取信息以及动态调用对象方法的功能称为java语言的反射机制。
        看这个官方的解释,说的很明白,就是在程序运行过程中,对实体类进行操作。包括操作其中的属性和方法。当然,这是我个人的理解。

如何利用反射构建对象

        既然我们知道了实体类的属性和方法,那我们就可以操作这个实体类了。具体怎么操作,我们慢慢来说,java的反射机制,其实依赖于一个对象,这个对象就是Class对象,中文名叫字节码对象。这个字节码对象就是一切反射的起点,不管你想用反射来干嘛,都要先获取这个字节码对象。然后才能进行后续的操作。先来一段简单的代码。尝尝鲜。
Java反射机制之反射构建对象以及给属性赋值_第1张图片
在这行代码中,
我们通过getClass方法获取到了list的字节码对象,并用一个字节码类型的变量去接收它。在获取字节码对象之后,我们就可以通过这个字节码对象来获取到类中的属性和方法。如图,我就通过字节码对象的getDeclaredMethod方法获取到了list所对应类型中的add方法。字节码对象中还有很多这样的方法,获取属性的,获取指定属性的,等等还有很多,这里就不在一一叙述了。
        我们注意到,我这里在获取字节码对象的时候,是直接获取的,因为我们知道我们需要获取哪个类型的字节码对象。但是有时候,我们完全不知道我们要反射的类是什么类。这个时候我们怎么办呢?
        这个时候,我们就用到了Class对象中的一个方法了。这个方法其实我们很熟悉,它就是Class.forName();方法。是不是很熟悉。这个方法在我们写jdbc的时候经常用到,但是我们从来没有了解过它是干嘛的,只知道这样写可以拿到数据库连接对象,为了对比,我先放两张图。
        这是图一
在这里插入图片描述
        这是图二
在这里插入图片描述
我们对比图一图二两张图,他们都用了Class.forName这个方法,其实用途看我的注释就可以知道了。它的作用就是将类加载到虚拟机上。这个方法有一个参数,是String类型。这个参数对应的就是要加载类的类路径。图一中就是数据库驱动对象在驱动包中的类路径,图二是我自己写的一个对象工厂,我让他加载我com.test.prictice包下的Mail这个类,把它加载到虚拟机中区。这个方法的返回值就是被加载类的字节码对象。因此我们只要知道类的绝对路径就可以通过这个方法来获取类的字节码对象。
        前边只是铺垫,开篇我们说了,要想利用反射,就必须依赖于字节码对象。所以我们要想利用反射构建对象,就得先获取字节码对象,现在字节码对象获取的方法,我们已经知道了。接下来,我们就可以构建对象了。
        Class对象中有一个方法,叫newInstance方法,看名字就知道是创建新实例的方法。我们可以通过这个方法来构建对象。代码如下。

利用无参构造方法构建对象

在这里插入图片描述
        这样我们就通过反射来构建了一个对象。我们也可以看到,newInstance方法的返回值是Object类型。
        这里又有一个问题,通过newInstance方法构建对象,目标类必须有无参构造方法。但是有时候我们的类会重写一个构造方法,这时候我们的无参构造方法就失效了。那怎么办的?其实很简单,前边已经说了,我们可以利用反射获取类中的属性和方法。我们只需要获取类中的有残构造方法就可以通过反射执行这个有参构造方法就可以构建对象了。代码如下:

利用有参构造方法构建对象

Java反射机制之反射构建对象以及给属性赋值_第2张图片
        注意,我图中圈起来的部分,圈起来的语句是设置方法的权限访问。因为有些类的构造方法会用private关键字修饰,这个时候,我们是无法直接获取方法的。属性同理。我们只能通过setAccessible方法设置方法的访问权限。然后再获取。这就体现了反射的一点缺陷。理论上反射可以访问任何类中的的任何方法或者属性,权限修饰符在它面前简直就是弟弟,想改就改了。反射就是爸爸,这样就导致了不安全的状态。
        好了,这就是通过反射来构造对象了。下面我们来说一说如何通过反射来为对象的属性赋值。

如何利用反射为对象的属性赋值

        其实通篇都看下来的小伙伴,脑子里肯定是已经有思路了。
        1.获取字节码对象
        2.利用对象的字节码对象获取对象中的属性。
        3.直接给属性赋值,或者获取属性对应的set方法为属性赋值。
        是不是很简单!!!对就是这么简单!!
        这里上面的情况我就不再说了。这里说说另一种情况。我们可能会遇到有一种类,它属性是private修饰的,也没有set和get方法。这个时候我们如何给他赋值呢。
        遇到这种情况的时候吗,我们一点都不用慌,前边已经说了,反射就是爸爸,什么都能干,private修饰我们给他改了不就可以了。没有set方法这个很好解决,上边我们提到,利用有参构造函数构造对象时获取了有参构造方法,在哪里,我们用了一个Constructor对象来接收构造方法,同理的,java中一样有接收字段的对象,叫Field,这个类中有对应的给字段赋值的方法。直接调用它的set方法就可以赋值了,它需要传两个参数,第一个参数是要赋值属性所属的对象,第二个就是要赋值的参数。当然,赋值之前不要忘记先把访问权限给修改了。好了,接下来,看代码:
Java反射机制之反射构建对象以及给属性赋值_第3张图片
        图中我是利用反射获取了注解中的值然后又通过反射给属性赋值。其实方法都一样。可以结合我上一篇文章:Java自定义注解的实现来看这段代码:https://blog.csdn.net/qq_39185919/article/details/97953815

你可能感兴趣的:(Java学习)