什么是反射机制
采用百度百科的定义:
JAVA反射机制是在运行状态中,对于任意一个实体类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意方法和属性;这种动态获取信息以及动态调用对象方法的功能称为java语言的反射机制。
Java的反射机制允许编程人员在对类未知的情况下,获取类相关信息的方式变得更加多样灵活,调用类中相应方法,是Java增加其灵活性与动态性的一种机制
在Java编程语言中,反射是一种强有力的工具,是面向抽象编程一种实现方式,它能使代码语句更加灵活,极大提高代码的运行时装配能力
-
原理
反射机制(Reflection)是Java提供的一项较为高级的功能,它提供了一种动态功能,而此功能的体现在于通过反射机制相关的API就可以获取任何Java类的包括属性、方法、构造器、修饰符等信息。元素不必在JVM运行时进行确定,反射可以使得它们在运行时动态地进行创建或调用
-
使用反射可以做什么
-
在运行过程中 分析类的能力;
比如这个类有什么样的属性,有什么样的方法 -
在运行中,可以查看和操作方法;
- 基于反射自由创建对象
- 反射构建出无法直接访问的类:比如构建方法是private的类,外界无法new出对象,但是通过反射可以构建这个对象的实例
- set或者get到无法访问的成员变量
- 调用不可访问的方法
-
实现通用的数组操作
java数组一旦创建,大小就不能变化了,可以通过反射实现数组的一个扩充器,达到修改数组大小的效果 -
类似函数指针的功能
可以将类中的方法封装成Method对象 传递给其他类进行调用
-
-
优点
-
反射机制极大的提高了程序的灵活性和扩展性,降低模块的耦合性,提高自身的适应能力;
-
通过反射机制可以让程序创建和控制任何类的对象,无需提前硬编码目标类;
-
使用反射机制能够在运行时构造一个类的对象、判断一个类所具有的成员变量和方法、调用一个对象的方法;
-
反射机制是构建框架技术的基础所在,使用反射可以避免将代码写死在框架中;
反射有以上的特征,所以它能动态编译和创建对象,极大的激发了编程语言的灵活性,强化了多态的特性,进一步提升了面向对象编程的抽象能力
-
缺点
- 性能问题
Java反射机制中包含了一些动态类型,所以Java虚拟机不能够对这些动态代码进行优化。因此,反射操作的效率要比正常操作效率低很多。我们应该避免在对性能要求很高的程序或经常被执行的代码中使用反射 - 安全限制
使用反射通常需要程序的运行没有安全方面的限制。如果一个程序对安全性提出要求,则最好不要使用反射 - 程序健壮性
反射允许代码执行一些通常不被允许的操作,所以使用反射有可能会导致意想不到的后果;
比如使用反射,我们可以修改成员属性的值,这样也许会破坏程序的结构,改变程序的执行方向
- 性能问题
三种获取Class对象的方式
- 通过类型获取,比如有一个A.java,我们可以通过A.class获取到Class对象
Class aClass = A.class; - 通过对象获取
A a = new A();
Class aClass = a.getClass(); - 通过全类名获取
Class aClass = Class.forName(全类名);
包信息和方法(常用的API)
Class对象的关键API
-
获取指定类名 name的Class对象
static Class Class.forName(String name) -
通过缺省构造方法,返回该Class对象的一个实例
T newInstance() -
返回该Class对象所表示的实体(类、接口、数组等)的名称
String getName() -
获取当前Class对象的父类的Class对象
Class getSuperClass() -
获取当前Class对象的接口
Class[] getInterfaces() -
返回该类的类加载器
ClassLoader getClassLoader() -
获取修饰符
int getModifiers() -
获取包信息
Package getPackage() -
类的实例化和构造函数
1.获取公有构造函数,不包括父类
//Class
public Constructor<?>[] getConstructors()
public Constructor getConstructor(Class<?>… parameterTypes)
2.获取当前类构造函数,忽略修饰符
//Class
public Constructor<?>[] getDeclaredConstructors()
public Constructor getDeclaredConstructor(Class<?>… parameterTypes)
3.构造函数调用
//Constructor
public T newInstance(Object… initargs) -
类成员变量的获取
1.获取公有变量,包括父类
//Class
public Field[] getFields()
public Field getField(String name)
2.获取当前类成员变量,忽略修饰符
//Class
public Field[] getDeclaredFields()
public Field getDeclaredField(String name)
3.成员变量赋值
//Field
//obj为实例对象
调用前先修改修饰符,避免私有的修饰符调用导致失败
setAccessible(true)
public void set(Object obj,Object value) -
忽略修饰符,强制调用
void setAccessible(boolean flag) -
类方法的获取
1.获取公有方法,包括父类
//Class
public Method[] getMethods()
public Method getMethod(String name,
Class<?>… parameterTypes)
2.获取当前类方法,忽略修饰符
//Class
public Method[] getDeclaredMethods()
public Method getDeclaredMethod(String name,
Class<?>… parameterTypes)
3.方法调用
//Method
//obj为类实例化对象,如果为静态方法obj为Null
调用前先修改修饰符,避免私有的修饰符调用导致失败
setAccessible(true)
invoke(Object obj, Object… args)