最近在看SpringIOC容器的源码,发现里面有使用java的反射和内省机制,这里记录和总结一下。反射(reflection)机制什么是反射反射是Java编程语言中的一个特性。它允许正在执行的Java程序检查或“内省”自身,并操纵程序的内部属性。例如,Java类可以获取其所有成员的名称并显示它们。因此,反射提供了以下功能:获取类定义的方法信息,包括方法名、参数、返回值等信息。获取类的构造函数。获取类的属性。通过方法名调用类对应的方法。修改对象的属性值。创建一个类对应的对象。反射涉及的类和接口所有与反射相关的类和接口都在java.lang.reflect包下,涉及的类和接口很多,无法一一介绍。下面主要介绍Class相关的。一个类主要包括构造函数(Constructor)、方法(Method)、字段(Field)、修饰符(Modifier)、接口(Interface)、父类(SuperClass)等组成部分。下面以Constructor和Method类为例。这两个类继承自同一个接口Executable。关系如下:AnnotatedElemnet接口标识了一个Java语言元素,可以用JavaAnnotation进行注解(包括Field、Parameter、Method、Constructor、Class、Package,表示类中的这些元素可以使用注解),该接口允许注释要通过反思来阅读。AccessibleObject类是Field、Method和Constructor的基类。在使用反射对象时,提供了Java语言访问控制检查的功能,同时可以关闭访问检查。当Field、Method和Constructor用于设置或获取字段、调用方法或创建和初始化类,分别。Member接口描述了Field、Method、Constructor需要实现的方法。通过这些方法,可以获得修饰符、名称、声明的类、是否被编译器引入等信息。GenericDeclaration接口也继承了AnnotatedElemnet,这是一个使用类型变量的公共接口。也就是说,只有实现了这个接口的人才可以在相应的“实体”上声明“泛型变量”。目前,实现GenericDeclaration接口的类包括Class(类)、Method(方法)、Constructor(构造函数),通过新增的getTypeParameters()方法获取泛型相关信息。Executable类是Constructor和Method的公共父类,包含一些公共方法。经过上面的分析我们可以知道,通过反射我们可以得到类相关的几乎所有信息,包括类拥有的字段、构造函数、方法、对应的修饰符,以及泛型信息,可以通过创建反射一个对象,调用一个方法,改变一个字段的值。反射中常用方法AccessibleObject常用方法方法名说明publicstaticvoidsetAccessible(AccessibleObject[]array,booleanflag)根据flag决定是否开启或关闭数组中对象的访问控制检查publicvoidsetAccessible(booleanflag)throwsSecurityException设置当前元素的访问检查标志publicbooleanisAccessible()返回当前元素的访问检查标志成员接口中定义的常用方法方法名说明publicStringgetName()获取当前元素的名称publicClass>getDeclaringClass()获取声明元素的ClasspublicintgetModifiers()获取当前元素的修饰符publicbooleanisSynthetic()如果该元素是编译器引入的则返回true,否则返回false可执行文件中定义的常用方法class方法名说明publicParameter[]getParameters()返回元素的参数列表publicintgetParameterCount()返回元素的参数个数publicabstractClass>[]getExceptionTypes()返回Class中常用的所有异常类型classMethod方法名说明publicField[]getFields()返回Class的所有可访问的公共字段,包括父类和接口的publicFieldClass根据名称publicField[]getDeclaredFields()throwsSecurityException返回元素声明的所有字段,包括public、default、protected、private,不包括父类和接口publicFieldgetDeclaredField(Stringname)throwsNoSuchFieldException,SecurityException根据名称找到与Class的声明字段匹配的字段publicConstructorgetConstructor(Class>...parameterTypes)根据指定的参数类型返回公共构造函数函数publicConstructor>[]getDeclaredConstructors()throwsSecurityException返回元素的所有构造函数,包括public、default、protected、private,不包括父类和接口publicMethod[]getMethods()throwsSecurityException返回所有可访问的public方法,包括父类的publicMethod[]getDeclaredMethods()throwsSecurityException返回元素所有声明的方法,包括public、default、protected、private,不包括父类和接口publicType[]getGenericInterfaces()直接返回实现的接口(含泛型参数)publicTypegetGenericSuperclass()返回直接继承的父类(含泛型参数)publicClass>[]getInterfaces()返回直接继承的父类(由于泛型擦除,不包含泛型参数)公共原生类getSuperclass()返回直接实现的接口(由于泛型擦除,不包含泛型参数)对于Constrcutor和Method,有类似的根据参数列表和方法名查找,Constructor和Method对应的方法没有一一列举。因为Constructor和Method继承自Executable抽象类,所以需要在Executable中实现抽象方法。常用的方法就是Executabel中的方法。注:以上方法仅为常用方法。此外,还有其他方法。可以查看reflect包下的java文件。反射的使用使用反射的步骤:创建一个Class//第一个方法Class>cls1=Student.class;//第二个方法Class>cls2=Class.forName("com.example.Student")使用反射的具体例子如下:获取所有方法信息。publicclassMethodExample{publicstaticvoidmain(String[]args)throwsClassNotFoundException{Class>cls=Class.forName("com.luoxj.Student");类>curClass=cls;while(curClass!=null){Method[]methods=curClass.getDeclaredMethods();for(Methodm:methods){System.out.println("================="+m.getDeclaringClass()+"===================");System.out.println("姓名:"+m.getName());System.out.println("声明类:"+m.getDeclaringClass());System.out.println("修饰符:"+Modifier.toString(m.getModifiers()));类>[]params=m.getParameterTypes();for(inti=0;i[]异常=m.getExceptionTypes();for(inti=0;icls=Class.forName("com.luoxj.Student");Class[]paramsType=newClass[3];paramsType[0]=String.class;paramsType[1]=Integer.TYPE;paramsType[2]=String.class;构造函数constructor=cls.getConstructor(paramsType);对象[]参数=新对象[3];参数[0]="鲍勃";参数[1]=10;参数[2]="天津大学";学生student=(Student)constructor.newInstance(params);System.out.println(student.toString());}catch(Throwablee){e.printStackTrace();}}}修改变量publicclassChangeFieldExample{publicstaticvoidmain(String[]args){try{Classcls=Class.forName("com.luoxj.Student");Fieldfld=cls.getDeclaredField("schoolName");学生学生=新学生();fld.setAccessible(真);fld.set(student,"天大");System.out.println("学校名="+student.getSchoolName());}catch(Throwablee){System.err.println(e);}}}什么是内省机制?Introspector类提供了一种标准方法来理解目标JavaBean支持的属性、事件和方法。JavaBean是指按照一定规范编写的Java类。具体规范包括:私有属性,Properties包括普通类型的属性,EventListener。默认无参构造函数的私有化属性可以通过setXxx、getXxx、addXxx、removeXxx、isXxx等类似方法设置或获取,其中EvenetListener的方法格式为addXxxEventListener、setXxxEventListener。getXxxEventListener、removeXxxEventListener等。也意味着我们可以通过内省机制获取类的JavaBean的属性、事件和方法。内省涉及的类和接口内省涉及的主要类和接口如下:Introspector类:提供一种标准的方式来获取JavaBeans支持的属性、事件和方法的信息。BeanInfo接口:定义了获取上述JavaBean信息的接口。FeatureDescriptor:是PropertyDescriptor、EventSetDescriptor和MethodDescriptor等的公共基类,支持一些可以设置和获取任意内省描述符的公共信息。FeatureDescriptor的主要属性有://expert表示当前Descriptor是针对专家还是普通用户privatebooleanexpert;//hidden表示当前Descriptor是给工具的还是普通用户的,如果是给工具的,应该隐藏,返回true。privatebooleanhidden;//preferred表示当前Descriptor对普通用户很重要privatebooleanpreferred;//简要说明privateStringshortDescription;//nameprivateStringname;//nameprivateStringdisplayName;//当前Descriptor相关属性私有Hashtable表;Introspection使用步骤:1.获取BeanInfo2,获取Descriptor具体例子如下:publicclassIntrospectorExample{publicstaticvoidmain(String[]args){BeanDescriptorbeanDescriptor=beanInfo.getBeanDescriptor();System.out.println("BeanName:"+beanDescriptor.getName());PropertyDescriptor[]propertyDescriptors=beanInfo.getPropertyDescriptors();for(PropertyDescriptorpropertyDescriptor:propertyDescriptors){ObjectdefaultValue=newObject();如果(propertyDescriptor.getPropertyType().equals(Integer.TYPE)){defaultValue=0;}否则如果(propertyDescriptor.getPropertyType().equals(String.class)){defaultValue="EmptyString";}propertyDescriptor.setValue("默认",defaultValue);System.out.println("name:"+propertyDescriptor.getName()+",displayName:"+propertyDescriptor.getDisplayName()+",type:"+propertyDescriptor.getPropertyType()+",isExpert:"+propertyDescriptor.isExpert()+",isConstrained:"+propertyDescriptor.isConstrained()+",isHidden:"+propertyDescriptor.isHidden()+",isPreferred:"+propertyDescriptor.isPreferred()+",isBound:"+propertyDescriptor.isBound()+",读取方法:"+propertyDescriptor.getReadMethod()+",writeMethod:"+propertyDescriptor.getWriteMethod()+",值:"+propertyDescriptor.getValue("默认"));}MethodDescriptor[]methodDescriptors=beanInfo.getMethodDescriptors();for(MethodDescriptormethodDescriptor:methodDescriptors){System.out.print("methodName:"+methodDescriptor.getName()+",methodDisplayName:"+methodDescriptor.getDisplayName()+",method:"+methodDescriptor.getMethod());ParameterDescriptor[]parameterDescriptors=methodDescriptor.getParameterDescriptors();if(null==parameterDescriptors){System.out.println();继续;}for(inti=0;i