文章目录
- 反射是什么?
- 反射有什么意义?
- 反射如何使用?
- Class类详解
-
- class类
- Class类常用方法
- 创建class对象
- 反射的应用场景
- 调用指定的方法
- 获取注解信息
- 提高反射效率
前言: 反射就像是一面镜子,这面镜子其实就是JVM,他能照出你的类的所有属性和方法,也能调用你所有对象的属性和方法, crazy~
java
是一门静态语言(运行时结构不变),不像
JavaScript,python...
那些动态语言一样,在运行时可以修改变量的值,但是java也可以称为
准动态语言
,因为他可以利用反射机制,获得类似动态语言的效果。
反射是什么?
- 先说正是怎么一回事。我要使用某个类,我必须要知道它是什么类,有何作用?用的时候,要先实例化。
//实例化一个对象,实例化的过程牵扯太多,不赘述
Student stu = new Studnt();
Class c1 = stu.getClass();
System.out.println(c1.getName());
- 上面这个Student类,JVM在加载的时候这个类的时候,其实会在JAVA堆中创建一个
的对象,就是上面的java.lang.class类
,这个class对象代表类的相关信息。可以使用这个对象的一些方法来获取类的相关信息,这里也体现出了万物皆对象的理念,连类都是对象。c1
- 看看class类,这还只是一小部分方法,跟类相关的都可以在Class类中找到。
JavaSE---反射反射是什么?反射有什么意义?反射如何使用?Class类详解反射的应用场景调用指定的方法获取注解信息提高反射效率 - 那说了这么多,反射到底是什么呢?
我的理解:在运行状态中,可以知道任意一个类的属性和方法,也可以调用任意一个对象的属性和方法,也就是动态获取信息,动态获取对象方法和属性,然而这些底层的实现细节都被屏蔽了,只留下API库给我们使用,也就是
java.lang.reflect
类库,这些API学习并不难,难在理解反射这个概念,由于实现细节都被屏蔽了,我们也就很少写到反射的代码。
反射有什么意义?
我直接
new
出来一个对象不就可以了,为什么用反射,要兜个大圈子?其实出去这些浅显表面的,反射真正的意义在于提高程序的灵活性,屏蔽底层实现细节,便于使用。
反射如何使用?
这个在使用的时候直接查API即可,常用的有以下几种。
- 通过一个对象获得完整的包名和类名。
- 实例化Class对象。
- 获取一个对象的父类与实现的接口。
- 获取某个类的全部构造函数。
- 通过反射机制实例化一个对象。
- 获取某个类的全部属性
- 获取某个类的全部方法
Class类详解
class类
- 对象照镜子后可以得到的信息:某个类的属性,方法,构造器,以及实现了哪些接口。
- 对每个类而言,JRE都为其保留一个不变的Class类型的对象,一个Class对象包含了特定某个结构(
)的有关信息。class/interface/enum/annotation/primitive type/void/[]
- Class本身也是一个类。
- Class对象只能由系统建立。我们只能通过反射去得到。
- 一个加载的类在JVM中只会有一个Class实例。
- Class类是Reflection的根源,如果你想动态加载,运行的类,只有先获得相应的class对象才可以。
Class类常用方法
方法名 | 功能说明 |
---|---|
| 返回指定类名name的Class对象 |
| 通过反射创建对象,返回Class对象的一个实例 |
| 返回Class对象所表示的实体(类,接口,数组的名称) |
| 返回当前Class对象的父类的Class对象 |
| 获取当前class对象的接口 |
| 返回该类的类加载器 |
| 返回一个包含某些Constructor对象的数组 |
创建class对象
创建class对象的三种方式
- 通过对象获得
- forname获得
- 通过类名.class获得
反射的应用场景
- JDBC(连接数据库与后端的桥梁),这其中就牵扯到一个连接的问题,我们将数据库的连接信息(用户名,用户密码,库名…)写在配置文件里,而不是写在代码里,为什么?因为这样我们更换数据库的时候,只需要改配置信息,而不是去改代码。而这里的由配置文件到代码,就是由反射来加载驱动的。
- Spring MVC,学
的时候各种servlet
获取信息,但是在SpringMVC框架中只需要在getParameter()
中约定好字段名,就可以把值填充进去。这就是反射的好处。javaBean
- Spring,这个我学的还不多,但是涉及到一个自动组装的问题,只要字段名的顺序是约定一致的,就可使实现自动组装的效果,就像一个萝卜一个坑一样。如果顺序颠倒,可能在你想象中组装出来的是超跑,但是现实却是拖拉机。
- Java的反射用的最多的地方就是在框架里面。比如说有两个程序员,他们各自创建了两个类,第一个程序员现在需要第二个程序员创建的类,可是现在第二个程序员创建的类还没有完成。那么第一个程序员编译自然不成功,但是现在第一个程序员又要使用第二个程序员的类,这个时候,反射就可以完成这个任务。因为反射是在类运行的时候获取对象的各个信息,所以第一个程序员的类就可以完成编译了。
调用指定的方法
- 通过反射,调用类中的方法,通过Method类完成。
- 获取到类的class对象。
- 通过Class对象调用
方法获取一个getMethod(String name, Class ...parameterTypes)
对象,并设置此方法操作时所需要的参数类型。Method
- 使用
进行调用,并向方法中传递要设置的obj对象的参数信息。Object invoke(Object obj,Object[] args)
-
:启动和禁用访问安全检查的开关。默认为false,设置为true之后,可以访问一些私有属性,可以提高反射的效率,如果代码中必须用反射,而该句代码需要频繁的被调用,就设置为true。setAccessible
获取注解信息
提高反射效率
- 反射比new对象慢,是因为Class.forName这个方法比较耗时,它实际上调用了一个本地方法,通过这个方法来要求JVM查找并加载指定的类。所以我们在项目中使用的时候,可以把Class.forName返回的Class对象缓存起来,下一次使用的时候直接从缓存里面获取,这样就极大的提高了获取Class的效率。同理,在我们获取Constructor、Method等对象的时候也可以缓存起来使用,避免每次使用时再来耗费时间创建。
- 还有一种更极致的使用反射手法,一个高性能反射工具包ReflectASM。它是通过字节码生成的方式来实现的反射机制
- 总结一下,为了更好的使用反射,我们应该在项目启动的时候将反射所需要的相关配置及数据加载进内存中,在运行阶段都从缓存中取这些元数据进行反射操作。如果对性能有极致追求的时候,可以考虑通过三方包,直接对字节码进行操作。