要想理解反射,首先得了解类的加载过程,看下图:
我们的源代码经过编译之后变成字节码,然后在JVM中运行时通过类加载器加载字节码在内存中生成Class类对象,这个Class类对象内包含有field对象(类的成员变量生成)、constructor对象(类的构造方法生成)和method对象(类的方法生成)。当我们拿到一个类或者对象的时候就可以通过反射对它们进行操作,下面再来看反射:
- 什么是反射
-
Java反射主要是指程序可以访问、检测和修改它本身状态或行为的一种能力,是Java被视为动态(或准动态)语言的一个关键性质。这个机制允许程序在运行时透过Reflection APIs取得任何一个已知名称的class的内部信息,包括其modifiers(诸如public, static 等)、superclass(例如Object)、实现之interfaces(例如Cloneable),也包括fields和methods的所有信息,并可于运行时改变fields内容或唤起methods。Java反射机制容许程序在运行时加载、探知、使用编译期间完全未知的classes。换言之,Java可以加载一个运行时才得知名称的class,获得其完整结构。
-
- 反射用在哪儿
- 多用于框架和组件,写出复用性高的通用程序。
- 如struts的form只要有了form对象和 property名字就可以利用反射给property赋值和取值 对这类操作 一个方法就可以搞定。如果hibernate不用字段进行反射映射 那么每个HQL的编译和结果处理 将无法进行等等。
- 多用于框架和组件,写出复用性高的通用程序。
- 怎么用
- 针对我们所知的不同情况分别有3种方法获取Class字节码对象
- 当已知类名的时候,通过 “类名.class”获得
- 当已知对象的时候,通过 “对象.getClass”获得
- 当已知包括包名在内的完整类名(假设为String格式)的时候,可通过 “Class.forName(String)”获得
- 获取Class字节码对象之后可以构造对象实例、获取对象中的属性对象、方法对象和构造函数对象
- 获取以上需要的各种对象之后就可以操作它们,进行增删改查等操作了。
- 针对我们所知的不同情况分别有3种方法获取Class字节码对象
- 优点与缺点是什么
- 优点
为什么要用反射机制?直接创建对象不就可以了吗,这就涉及到了动态与静态的概念,静态编译:在编译时确定类型,绑定对象,即通过。动态编译:运行时确定类型,绑定对象。动态编译最大限度发挥了java的灵活性,体现了多态的应用,用以降低类之间的藕合性。一句话,反射机制的优点就是可以实现动态创建对象和编译,体现出很大的灵活性,特别是在J2EE的开发中 它的灵活性就表现的十分明显。比如,一个大型的软件,不可能一次就把把它设计的很完美,当这个程序编译后,发布了,当发现需要更新某些功能时,我们不可能要用户把以前的卸载,再重新安装新的版本,假如这样的话,这个软件肯定是没有多少人用的。采用静态的话,需要把整个程序重新编译一次才可以实现功能的更新,而采用反射机制的话,它就可以不用卸载,只需要在运行时才动态的创建和编译,就可以实现该功能。
- 缺点
它的缺点是对性能有影响。使用反射基本上是一种解释操作,我们可以告诉JVM,我们希望做什么并且它满足我们的要求。这类操作总是慢于只直接执行相同的操作。
- 例子
- 获取Class字节码对象的方法
- 操作构造方法
- 操作成员变量
- 操作普通方法
Java语言反射提供一种动态链接程序组件的多功能方法。它允许程序创建和控制任何类的对象,无需提前硬编码目标类。这些特性使得反射特别适用于创建以非常普通的方式与对象协作的库。Java reflection 非常有用,它使类和数据结构能按名称动态检索相关信息,并允许在运行着的程序中操作这些信息。Java 的这一特性非常强大,并且是其它一些常用语言,如 C、C++、Fortran 或者 Pascal 等都不具备的。
由于用于字段和方法接入时反射要远慢于直接代码,反射在性能上会有所影响,但性能问题的程度取决于程序中是如何使用反射的。如果它作为程序运行中相对很少涉及的部分,缓慢的性能将不会是一个问题。即使测试中最坏情况下的计时图显示的反射操作只耗用几微秒。仅反射在性能关键的应用的核心逻辑中使用时性能问题才变得至关重要。所以,合理的使用反射将大大提高我们程序的通用性和复用性。