反射: Refelection,反射是Java的特征之一,允许运行中的Java程序获取自身信息,并可以操作类或者对象的内部属性
通过反射,可以在运行时获得程序或者程序中的每一个类型的成员活成成员的信息
程序中的对象一般都是在编译时就确定下来,Java反射机制可以动态地创建对象并且调用相关属性,这些对象的类型在编译时是未知的
也就是说 ,可以通过反射机制直接创建对象,即使这个对象类型在编译时是未知的
Java反射提供下列功能:
在运行时判断任意一个对象所属的类
在运行时构造任意一个类的对象
在运行时判断任意一个类所具有的成员变量和方法,可以通过反射调用private方法
在运行时调用任意一个对象的方法
反射的原理反射的核心: JVM在运行时才动态加载类或者调用方法以及访问属性,不需要事先(比如编译时)知道运行对象是什么
类的加载:
Java反射机制是围绕Class类展开的
首先要了解类的加载机制:
JVM使用ClassLoader将字节码文件,即 class文件加载到方法区内存中
Class clazz = ClassLoader.getSystemClassLoader().loadClass("com.mypackage.MyClass");ClassLoader类根据类的完全限定名加载类并返回一个Class对象
ReflectionData:
为了提高反射的性能,必须要提供缓存
class类内部使用一个useCaches静态变量来标记是否使用缓存
这个值可以通过外部的sun.reflect.noCaches配置是否禁用缓存
class类内部提供了一个ReflectionData内部类用来存放反射数据的缓存,并声明了一个reflectionData域
由于稍后进行按需延迟加载并缓存,所以这个域并没有指向一个实例化的ReflectionData对象
// 标记是否使用缓存,可以通过外部的sun.reflect.noCaches配置是否禁用缓存 private static boolean useCaches = true; static class ReflectionData<T> { volatile Field[] declaredFields; volatile Field[] publicFields; volatile Method[] declaredMethods; volatile Method[] publicMethods; volatile Constructor<T>[] declaredConstructors; volatile Constructors<T>[] publicConstructors; volatile Field[] declaredPublicFields; volatile Method[] declaredPublicMethods; final int redefinedCount; ReflectionData(int redefinedCount) { this.redefinedCount = redefinedCount; } } // 这个是SoftReference,在内存资源紧张的时候可能会被回收 // volatile保证多线程环境下读写的正确性 private volatile transient SoftReference<RefelectionData<T>> reflectionData; // 这个主要用于和ReflectionData中的redefinedCount进行比较 // 如果两个值不相等,说明ReflectionData缓存的数据已经过期了 private volatile transient classRedefinedCount = 0; 反射的主要用途反射最重要的用途就是开发各种通用框架
很多框架都是配置化的,通过XML文件配置Bean
为了保证框架的通用性,需要根据配置文件加载不同的对象或者类,调用不同的方法
要运用反射,运行时动态加载需要加载的对象
示例:
在运用Struts 2框架的开发中会在struts.xml中配置Action:
<action method="execute"> <result>/shop/shop-index.jsp</result> <result>login.jsp</result> </action>配置文件与Action建立映射关系
当View层发出请求时,请求会被StrutsPrepareAndExecuteFilter拦截
StrutsPrepareAndExecuteFilter会动态地创建Action实例
请求login.action
StrutsPrepareAndExecuteFilter会解析struts.xml文件
检索action中name为login的Action
根据class属性创建SimpleLoginAction实例
使用invoke方法调用execute方法
反射是各种容器实现的核心
反射的运用反射相关的类在StrutsPrepareAndExecuteFilter包
反射可以用于:
判断对象所属的类
获得class对象
构造任意一个对象
调用一个对象
九大预定义的Class对象:
基本的Java类型: boolean, byte, char, short, int, long, float, double
关键字void通过class属性的也表示为Class对象
包装类或者void类的静态TYPE字段:
Integer.TYPE == int.class
Integer.class == int.class
数组类型的Class实例对象:
Class<String[]> clz = String[].class;
数组的Class对象如何比较是否相等:
数组的维数
数组的类型
Class类中的isArray(),用来判断是否表示一个数组类型
获得Class对象使用Class类的forName静态方法:
public static Class<?> forName(String className); /* 在JDBC中使用这个方法加载数据库驱动 */ Class.forName(driver);直接获取一个对象的class:
Class<?> klass=int.class; Class<?> classInt=Integer.TYPE;调用对象的getClass()方法:
StringBuilder str=new StringBuilder("A"); Class<?> klass=str.getClass(); 判断是否是某个类的实例一般来说,使用instanceof关键字判断是否为某个类的实例