目录
1. 定义
2. 用途
3. 反射基本信息
4. 反射相关的类
4.1 class类(反射机制的起源)
4.1.1 Class类中的相关方法(方法的具体使用在后面的示例中)
4.2 反射的示例
4.2.1 获得Class对象的三种方式
4.2.2 反射的使用
Field类的使用:
Construct类的使用:
Method类的使用:
5. 反射的优点和缺点
1. 定义
Java的反射(reflection) 机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法,对于任意一个对象,都能够调用它的任意方法和属性,既然能拿到对应的属性和方法,就可以对部分类型信息进行修改。这种动态获取信息以及动态调用对象的方法的功能称为Java语言的反射(reflection)机制。
2. 用途
1.在日常的第三方应用开发过程中,经常会遇到某个类的某个成员变量、方法或者属性是私有的或是只对系统应用开放,这时候就可以利用Java的反射机制通过反射来获取所需要的私有成员或是方法。
2.反射最重要的用途就是开发各种通用框架,比如在spring中,将所有的类Bean交给spring容器管理,无论是XML配置Bean还是注解配置,当我们从容器中获取Bean来依赖注入时,容器会读取配置,而配置中给的就是类的信息,spring根据这些信息,需要创建那些Bean,spring就动态的创建这些类。
3. 反射基本信息
Java程序中许多对象在运行时会出现两种类型,运行时类型(RTTI)和编译时类型,例如Person p = new Student(); 这句代码中 p 在编译时类型为Person,但在运行时类型为Student。程序员需要在运行时发现对象和类的真实信息,而通过使用反射程序就能判断出该对象和类属于那种类型。
4. 反射相关的类
4.1 class类(反射机制的起源)
文档如下:类 |API 参考 |Android 开发人员
Class代表类的实体,在运行的Java应用程序中表示类和接口
Java文件被编译后,生成了.class文件,JVM此时就要去解读.class文件,被编译后的java文件.class也被JVM解析为一个对象,这个对象就是java.lang.Class,这样当程序在运行时,每个java类就最终变成了Class类对象的一个实例。我们通过Java的反射机制应用到这个实例,就可以获得甚至取添加改变这个类的属性和动作,使这个类成为一个动态的类。
解读:
4.1.1 Class类中的相关方法(方法的具体使用在后面的示例中)
1.常用获得类相关的方法(重要)
2.常用获得类中属性相关的方法(重要)
3.获得类中注解的方法(重要)
4.获得类中构造器相关方法(重要)
5.获得类中方法的相关方法(重要)
4.2 反射的示例
4.2.1 获得Class对象的三种方式
在反射之前,需要做的第一步就是先拿到当前需要反射的类的Class对象,然后通过Class对象的核心方法,达到反射的目的,即:在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意方法和属性,既然能拿到,那么我们还可以修改部分类型信息。
第一种:使用Class.forName("类的全路径名"); 静态方法。
前提:已明确类的全路径名。
第二种:使用.class方法。
说明:仅适合在编译前就已经明确要操作的Class
第三种:使用类对象的getClass()方法
示例如下:
首先我们要有一个类Student
第一种:
这种情况是直接通过Class对象的forName()静态方法来进行获取,但可能抛出异常,需要注意的是,forName方法中的参数是类的全路径,如果在某个包下,需要加上对应包的路径
forName方法:可以在源码中看到是静态方法,其返回值是Class<?>
第二种:直接通过类名.class方式获得Class对象,这种方法的安全性比较高,也侧面说明,每一个类都有一个静态成员变量class
第三种:getClass获得Class对象
上面就是三种获得Class对象的具体方法。需要知道的是,一个类在JVM中只会有一个Class实例,即我们对上面获取的c1 c2 c3进行equals比较 结果都是true
4.2.2 反射的使用
Field类的使用:
下面是用反射来实例化一个对象的示例:
在该示例中,Class<?> c1创建一个Class对象,然后用forName方法,输入Student的全路径,得到Class对象,之后调用c1的newInstance方法来实例化对象,同样的,newInstance也会抛出异常
测试:
这里可以看到可以正常获得Student类的默认name和age
Construct类的使用:
下面是使用反射机制来访问并且调用Student类的私有构造方法的实例
代码如下:
改代码使用了Java的反射机制来访问并且调用了reflectdemo包下的Student类的私有构造方法,从而创建了Student类的一个实例。
首先仍然是创建Class对象,并且使用forName获取Student类
然后是获取私有构造方法。通过Class对象的getDeclaredConstructor方法获取到了Student类中参数为String和int的构造方法。getDeclaredConstructor方法可以获取包括私有构造方法在内的所有构造方法。需要将getDeclaredConstructor的返回值进行一个强转(Constructor<Student>),以明确表示这是Student类的构造方法。
既然我们可以获取到,就可以对其进行修改,但毕竟是私有构造方法,我们需要调用setAccessible方法设置为true,来确认我们是要调用该私有方法的。如果没有该方法的调用,是无法在下文对Student类实例化的。
然后就可以在其他类中创建一个Student类的实例了。并且使用的是Student的private构造方法
对应的方法也需要抛出对应的异常。
main方法中测试符合预期:
Method类的使用:
接下来的是使用反射机制来访问Student类的私有方法示例
代码如下:
此处直接调用了function这个私有函数,并且成功进行了传参
5. 反射的优点和缺点
优点:
1.对于任意一个类,都能知道这个类的所有属性和方法,对于任意一个对象,都能够调用它的任意一个方法。
2. 增加程序的灵活性和拓展性,降低耦合性,提高自适应能力。
缺点:
1.使用反射会有效率问题。可参考文章:大家都说 Java 反射效率低,你知道原因在哪里么_慕课手记
2.反射计数绕过了源代码的技术,因而会带带来维护问题。反射代码比相应的直接代码更加复杂。
完!