这篇文章我们来讲一下java的代理与反射,这是很重要的一部分内容。
目录
1.什么是反射
2.获取class对象的三种方式
3.反射获取构造方法
4.利用反射来获取成员变量
5.利用反射来获取成员方法
6.反射的作用
7.反射小结
1.什么是反射
首先,我们来看一下什么是反射
官方定义:反射允许对封装类的字段,方法和构造函数的信息进行编程访问
解释:反射允许对成员变量,成员方法和构造方法的信息进行编程访问
说人话:就是反射可以把类里面的所有信息都获取出来,并对获取出来的信息进行操作。
反射的用处举例:
idea里面的自动提示功能:
idea中的方法参数提示功能(快捷键:Ctrl+P):
问:从类里面拿东西,IO流也行,为什么要用反射呢?
答:IO流无法判断类的构造函数和普通方法,无法判断同名的成员变量和方法中的变量。
反射要学习的内容:
2.获取class对象的三种方式
获取class对象有三种方式:
- Class.forName(“全类名”)
- 类名.class
- 对象.getClass()
注意:我们通过反射获取的不是.java文件,获取的是.class字节码文件,然后我们在.class字节码文件中找到类的相应信息,然后对这些信息进行操作
下面,我们来看一下一个类的三个阶段:
解析:首先,我们编写一个.java文件,然后它会被JVM编译成.class文件,这个阶段是在硬盘中实现的,这个阶段也称为源代码阶段。然后,我们运行程序,.class被拿到内存中加载,这个阶段是加载阶段,然后,我们创建对象,计算机就会在内存中创建出类的实例化对象,这个阶段就是运行阶段。其中,这三个阶段分别对应了上面反射获取类的三种方式。
下面,用代码来具体的演示一下这三种方式:
有一个疑问,它为什么是true?首先,我要明白我们通过反射获取的是什么?我们获取的是类的.class字节码文件,我们获取它干啥?我们通过获取这个类的字节码文件然后分析然后来获取类的信息,所以,我们通过反射最终获取的是类的信息,因为这是同一个类,所以它的信息是一样的,所以是true!
3.反射获取构造方法
上面,我们讲了如何获取类的字节码文件,现在,我们来讲一下如果在类的字节码文件中获取类的构造方法信息。
我们知道,java的思想是万物皆对象,我们通过反射获取类的字节码文件,那么就用Class类对象来接收它,我们获取类的构造方法,那就通过Constructor类对象来接收它,我们获取类的字段(成员变量),那就通过Field类对象来接收它,我们获取类的成员方法,那就通过Method类对象来接收它。
下面,我们来看一下用反射获取类的构造方法的方法:
(这些方法的格式和javaAPI的格式是一样的,可以按照那个的格式来理解)
下面通过具体实例来看一下里面的一些方法的使用:
然后看一下运行结果:
再看一下利用构造方法中的类来创建对象:
结果:
注意:我们在调用这些方法的时候,它获取的内容或受到权限修饰符的限制,也就是说,当我们用不同的方法虽然获取的都是构造方法,但是构造方法的权限修饰符不一样,而导致最终的结果也会不一样。并且,我们用这些构造方法的对象中的类来创建对象时,也会受到权限修饰符的影响,甚至受到形参的影响,但是这些都是小问题,我们在具体运用时是可以自己解决的,所以我上面就没有演示那些问题的案例。
4.利用反射来获取成员变量
上面已经具体的讲过了反射获取类信息的本质,所以这里就不多说了。
下面,我们来看一下利用反射来获取成员变量的方法:
下面通过具体案例来演示一下:
看一下结果:
再用它来创建对象看一下:
还是要注意权限修饰符
5.利用反射来获取成员方法
下面,我们来看一下利用反射来获取成员方法的方法:
下面,还是来看一下具体实例吧
结果:
6.反射的作用
反射的作用主要有以下两点:
- 获取一个类里面所有的信息,获取到了之后,再执行其他的业务逻辑
- 结合配置文件,动态的创建对象并调用方法
下面通过具体的代码案例来演示下反射的这两个作用
案例一:对于任意一个对象,都可以把对象所有的字段名和值,保存到文件中去
代码如下:
结果如下:
案例二:反射可以跟配置文件结合的方式,动态的创建对象,并调用方法
代码如下:
运行结果:
7.反射小结
下面来小结一下反射(自己的理解)
首先,我们要区分类和对象,类是模板,对象是类的实例化。我们反射获取的是类的.class文件,不是对象。我们知道java有.java文件(就是我们自己写的)和.class字节码文件(JVM编译的),我们反射获取的是类的.class字节码文件,我们获取到它后就可以分析解剖它,说白了就是获取类的所有信息,于是,我们可以通过反射来获取类的成员变量,成员方法,构造方法(实际上是从类的.class字节码文件中获取的)。而java又是面向对象的,所以我们获取出来这些信息后,又把这些信息全部封装到类中,于是有了Constructor,Field,Method类,有了这些类我们就可以创建这些类的对象,然后通过对象和类里面的方法,就可以把那些信息给拿出来了。注意,我们通过获取.class字节码文件然后获取类的那些信息,我们是直接拿不出来的,那些信息都被封装在类里面。因为我们有了这些类的对象,而这些对象里面都是可以操作我们手写类的方法,所以我们就可以通过这些类的对象来创建我们手写类的对象了。就比如,我们有了Constructor类对象,它是我们构造方法类对象,所以呢我们就可以通过这个对象来操作我们的手写类的构造方法,然后就创建出对象了。Field类对象也一样,我们有一个手写类对象,我们把这个类对象传进去,然后调用Field类对象方法,就可以修改对象的成员变量值了。Method的类对象的逻辑也是一样的。这上面就是反射的基本逻辑。但是有些细节我们需要注意:比如说权限修饰符的问题,比如说方法的重载,这些都是细节问题,都需要注意!