在Java技术体系中所提供的能够让我们在运行时识别对象和类的类型信息的方式,一共有两种:即反射和多态关键技术RTTI。
多态和反射两者的最大的共同点在于,他们都是运行时获取程序信息的技术。
多态
多态是面向对象编程里面的概念,一个接口的多种不同的实现方式,即为多态。
多态体现在:只有在运行的时候才知道引用变量所指向的具体实例对象。且有三个必要的条件:
- 继承
- 重写/实现
- 父类引用指向子类对象
java里多态的具体用法
- 子类继承父类(extends)
- 类实现接口(implements)
==========【要使用多态,在声明对象时就应该遵循一条法则:声明的总是父类类型或接口类型,而创建的是实际类型.】
反射
java程序在运行状态中,对于任意一个类,都能够在运行时知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意方法和属性;这种动态获取信息以及动态调用对象方法的功能称为java语言的反射机制。
反射的实现原理
Class类与java.lang.reflect库一起对反射的概念提供了技术支持。java.lang.reflect
类库包含了Field类,Method类以及Constructor类。这些类用来表示未知类里对应的成员。Class类提供了获取getFields()
、getMethods()
和getConstructors()
等方法,而这些方法的返回值类型就定义在java.lang.reflect
当中。
反射机制并没有什么神奇之处,当通过反射与一个未知类型的对象打交道时,JVM只是简单地检查这个对象,看它属于哪个特定的类,然后再通过拿到的某一个类的全限定名去找这个类的Class文件 。因此,那个类的.class对于JVM来说必须是可获取的,要么在本地机器上,要么从网络获取。
- RTTI,编译器在编译时打开和检查.class文件
- 反射,运行时打开和检查.class文件
java虚拟机帮我们生成了类的class对象,而通过类的全限定名,我们可以去获取这个类的字节码.class文件,然后再获取这个类对应的class对象,再通过class对象提供的方法结合类Method,Filed,Constructor,就能获取到这个类的所有相关信息. 获取到这些信息之后,就可以使用Constructor创建对象,用get和set方法读取和修改与Field对象相关的字段,用invoke方法调用与Method对象关联的方法。
反射的应用
- Spring/Mybatis等框架,行内有一句这样的老话:反射机制是Java框架的基石。最经典的就是xml的配置模式。
- JDBC 的数据库的连接
- 动态生成对象,应用于工厂模式中. spring的bean容器也就是一个工厂
- jdk动态代理,利用反射获取传入接口的实现类
- 注解机制的实现,利用反射可以获取每一个filed,Filed类提供了getDeclaredAnnotations方法以数组形式返回这个字段所有的注解....
- 编辑器代码自动提示的实现
反射的弊端
1.性能
反射包括了一些动态类型,所以 JVM 无法对这些代码进行优化。因此,反射操作的效率要比那些非反射操作低得多。我们应该避免在经常被 执行的代码或对性能要求很高的程序中使用反射。
2.安全
使用反射技术要求程序必须在一个没有安全限制的环境中运行。如果一个程序必须在有安全限制的环境中运行,如 Applet,那么这就是个问题了。
3.内部暴露
由于反射允许代码执行一些在正常情况下不被允许的操作(比如访问私有的属性和方法),所以使用反射可能会导致意料之外的副作用--代码有功能上的错误,降低可移植性。反射代码破坏了抽象性,因此当平台发生改变的时候,代码的行为就有可能也随着变化。
4.丧失了编译时类型检查的好处,包括异常检查。如果程序企图用反射去调用不存在或者不可访问方法,在运行时将会失败。
反射相关类
Class类
Field类
字段类,我们可以通过一个类的Class对象获取其Field类的对象,然后java当中提供了这个Field类来提供反射获取字段的相关信息,以及进行一些操作。
Method类
即方法类,我们可以通过一个类的Class对象获取其Method类的一个实例对象,并且使用获得的Method对象去获取这个方法的相关信息,以及调用这个方法的功能。
反射和多态的区别
- 同为运行时获取信息,多态获取的信息仅仅在于确定方法应用所指向的实际对象。而反射在于获取一个类的所用信息。
- 多态是一种面向对象语言的机制。而反射技术是java提供的专门用于动态获取类的信息的技术。