一、概念
反射是什么?简单来说就是Java中将类的各个组成部分封装为一种特殊的对象,然后在程序运行过程中其它类都能通过这种特殊对象调用该类的成员方法和成员变量,这就是反射的过程。这也是Java作为动态语言的一个关键特性。
二、运行原理
首先我们需要简单了解一般Java代码在计算机中经历的过程。
在Java中,我们编写的程序代码需要在计算机中经历三个阶段,首先是源代码阶段,我们编写一个java类然后通过javac编译得到对应class文件,然后就进入了class类对象阶段,虚拟机通过类加载器把class文件中的成员变量封装为Field对象,把构造方法封装为Constructor对象,把成员方法封装为Method对象,得到这三种class类对象然后就进入运行阶段,运行时我们就new一个我们编写的这个对象。
上面是一般Java代码在计算机中经历的阶段,而反射其实就是我们在其它类中直接调用Java虚拟机构造出来的三种Class对象,而实现直接对成员方法和成员变量的操作。其实这样的机制一定程度上破坏了Java的封装性。
三、获取Class对象
在上面的运行原理中,我们提到了反射是通过获取类的三种Class对象实现的。获取Class对象是运用反射的第一步,如何获取类的Class对象,下面介绍获取Class对象的三种方法。
1. 通过 Class.forName(CompleteClassName)
2. 通过 ClassName.Class
3. 通过 对象.getClass()
注:CompleteClassName代表的是class文件在src文件下的包含包名的完全类名。 ClassName代表就是简单的类名
上述的三种获取Class对象的方法其实都是获取的同一个class对象,因为一个java文件在程序运行中只会编译一次,就是初次的类加载进内存的时候,所以获取的对象一定是相同的。
三种获取Class对象的代码示例:
//method1
Class cls1=Class.forName("mei.Reflect.Person");
//method2
Class cls2=Person.class;
//method3
Person p=new Person();
Class cls3=p.getClass();
四、Class对象的使用
获取的Class对象,我们就可以获取其中的三个对象,分别是Field、Constructor、Method。api如下
- 获取成员变量
Field[] getFields()
Field getField(String name)
Field[] getDeclaredFields()
Field getDeclaredField(String name) - 获取构造方法
Constructor<?>[] getConstructors()
Constructor getConstructor(Class<?>… parameterTypes)
Constructor getDeclaredConstructor(Class<?>… parameterTypes)
Constructor<?>[] getDeclaredConstructors() - 获取成员方法们:
Method[] getMethods()
Method getMethod(String name, 类<?>… parameterTypes)
Method[] getDeclaredMethods()
Method getDeclaredMethod(String name, 类<?>… parameterTypes) - 获取完整类名
String getName() .
获得方法或者变量后,我们可以对其进行newinstance、set或get等一系列操作。
五、优缺点及其应用
1、优点:
使用反射,我们就可以在运行时获得类的各种内容,进行反编译,对于Java这种先编译再运行的语言,能够让我们很方便的创建灵活的代码,这些代码可以在运行时装配,无需在组件之间进行源代码的链接,更加容易实现面向对象。
2、缺点:
a. 反射会消耗一定的系统资源,因此,如果不需要动态地创建一个对象,那么就不需要用反射;
b. 反射调用方法时可以忽略权限检查,因此可能会破坏封装性而导致安全问题。
3、应用
利用反射的优点就可以很好的利用反射。Java反射技术应用场合很多,如许多常用的框架比如Struts、Hibernate、Spring在实现过程中都频繁使用了发射技术。所以我们必须得深刻了解反射才能更好的学习框架。
4、IDEA中随处可见的反射