java中一个强大的功能,莫过于反射了。通常我们看看的Struct2、Struct1、Spring、Hibernate等等集合无一不使用了反射机制。那么什么是反射呢,到底有什么用呢?
一、反射机制概念
简单的讲,反射就是通过把指定的类中各种元素成分都映射成相关的反射包中的相应类,使得我们可以动态的调用类的相应成员,比如构造方法、成员方法、成员变量等。它被视为动态(或准动态)语言的一个关键性质。这个机制允许程序在运行时透过Reflection APIs取得任何一个已知名称的class的内部信息,包括其modifiers(诸如public, static 等)、superclass(例如Object)、实现之interfaces(例如Cloneable),也包括fields和methods的所有信息,并可于运行时改变fields内容或唤起methods。
Java反射机制容许程序在运行时加载、探知、使用编译期间完全未知的classes。
换言之,Java可以加载一个运行时才得知名称的class,获得其完整结构。
二、反射的功能:
2.1在运行时判断任意一个对象所属的类 如 aclass.getClass() == bclass.getClass()
2.2在运行时构造任意一个类的对象 如Class.forName(className).netInstance(),className是运行时才得出来的类名
2.3在运行时判段任意一个类所具有的成员变量和方法
2.4在运行时调用任一个对象的方法
2.5在运行时创建新类对象
三、反射API中重点的几个类
Class:Class 类的实例表示正在运行的 Java 应用程序中的类和接口。枚举是一种类,注释是一种接口。每个数组属于被映射为 Class 对象的一个类,所有具有相同元素类型和维数的数组都共享该Class 对象
没有构造方法,具体如何获取Class对象的实例,下面的示例代码中将会总结。
常用的方法用:
T cast(Object obj) 、static Class> forName(String className) 、 ClassLoader getClassLoader() 、 Constructor getConstructor(Class>... parameterTypes) 、
Constructor>[] getConstructors() 、 Constructor getDeclaredConstructor(Class>... parameterTypes)、 Constructor>[] getDeclaredConstructors() 、
Field getDeclaredField(String name)、 Field[] getDeclaredFields() 、Method getDeclaredMethod(String name, Class>... parameterTypes)
Method[] getDeclaredMethods() 、Field getField(String name) 、 Field[] getFields() 、 Method getMethod(String name, Class>... parameterTypes)
Method[] getMethods() 、int getModifiers() 、String getName() 、InputStream getResourceAsStream(String name)、 boolean isArray() 、T newInstance()
Constructor:Constructor 提供关于类的单个构造方法的信息以及对它的访问权限
没用构造方法,一般都是通过Class对象中的相应类来获得Constructor对象的。
常用的方法:
Class getDeclaringClass() 、Class>[] getExceptionTypes() 、Type[] getGenericExceptionTypes()、Type[] getGenericParameterTypes() 、
int getModifiers() 、String getName() 、Class>[] getParameterTypes() 、boolean isVarArgs() 、 T newInstance(Object... initargs)
Method:Method 提供关于类或接口上单独某个方法(以及如何访问该方法)的信息。所反映的方法可能是类方法或实例方法(包括抽象方法)。
没有构造方法,也是通常Class对象中相应的方法来获取Method对象。
常用的方法:
Class> getDeclaringClass() 、int getModifiers() 、String getName() 、Class>[] getParameterTypes()
Class> getReturnType() 、Object invoke(Object obj, Object... args)
Field:Field提供有关类或接口的单个字段的信息,以及对它的动态访问权限。反射的字段可能是一个类(静态)字段或实例字段。
没有构造方法,也是通常Class对象中相应的方法来获取Method对象。
常用的方法:
Object get(Object obj) 、 int getModifiers() 、String getName() 、Class> getType() 、 void set(Object obj, Object value)。另外还支持相应的int getInt(Object obj)
与void setInt(Object obj, int value)等相应的直接对基本数据类型进行操作。
Modifier:Modifier 类提供了static 方法和常量,对类和成员访问修饰符进行解码。
这是没有构造方法的,都是通过相应的Class、Constructor、Method、Field类对象得到的,且常用的方法static boolean isPublic(int mod) 、static boolean isPrivate(int mod) 等,用个方法是static String toString(int mod)蛮好用的,此方法是返回描述指定修饰符中的访问修饰符标志的字符串。
四、反射举例代码:
在使用Java的反射功能时,基本首先都要获取类的Class对象,再通过Class对象获取其他的对象
- package com.enhance;
- import java.lang.reflect.Constructor;
- import java.lang.reflect.Field;
- import java.lang.reflect.Method;
- import java.lang.reflect.Modifier;
- import java.util.ArrayList;
- import java.util.Arrays;
- import java.util.List;
-
- public class ReflectDemo {
-
- private int pos ;
- public String name;
-
- private int size ;
- private final static double PI = 3.1415926;
-
- private ArrayList alist = new ArrayList();
-
-
-
-
-
-
- public static double getPI(){
- return PI;
- }
-
-
-
-
-
- public static void main(String[] args) throws Exception {
- getClassTest();
- applyReflectChangeObjValDemo();
- reflectInvorkArrayDeom();
-
- printClass("java.lang.String");
- arraysAsListTest();
-
- }
-
- public static void getClassTest() throws Exception{
-
-
-
-
-
-
-
-
- String str1 = "abc";
- Class c1 = str1.getClass();
- Class c2 = String.class;
- Class c3 = Class.forName("java.lang.String");
-
- System.out.println("c1==c2::"+(c1==c2));
- System.out.println("c2==c3::"+(c2==c3));
-
-
- System.out.println("c1.isPrimitive()=="+c1.isPrimitive());
-
- Class c4 = int.class;
- System.out.println("c1.isPrimitive()=="+c4.isPrimitive());
- System.out.println("c3==c4::"+(c3==c4));
-
- Class c5 = Integer.TYPE;
- System.out.println("c4==c5::"+(c4==c5));
-
-
-
-
- Class strCl = Class.forName("java.lang.String");
- Constructor strCon = strCl.getConstructor(StringBuilder.class);
- String str = (String)strCon.newInstance(new StringBuilder("sdf"));
- String strr = (String)strCl.newInstance();
-
- }
-
- private static void arraysAsListTest() {
- int[] a1 = new int[]{4,5,6};
- List l1 = Arrays.asList(a1);
-
-
- System.out.println(l1+"-----------"+l1.size());
- for(int i=0;i
-
- System.out.print(l1.get(i)+" ,");
- }
- }
-
-
-
-
-
-
-
-
-
-
-
- private static void reflectInvorkArrayDeom() {
- ReflectDemo rd = new ReflectDemo();
-
- Method m1 = null ;
- try{
- Class lc = rd.getClass();
- int[] intArr = new int[]{3,5};
- m1 = lc.getMethod("printIntArray", int[].class);
- m1.invoke(rd, intArr);
-
- String[] strArr = new String[]{"abc","bcd"};
- m1 = lc.getMethod("printStringArray", String[].class);
-
-
-
-
-
- m1.invoke(rd, (Object)strArr);
-
-
- m1.invoke(rd, new Object[]{strArr});
-
-
- Integer[] integerArr = new Integer[]{12,56};
- m1 = lc.getMethod("printIntegerArray", Integer[].class);
-
- m1.invoke(rd, (Object)integerArr);
- }catch(Exception e){
- e.printStackTrace();
- }
-
- }
-
-
-
-
-
- private static void printClass(String className) {
- ArrayList al = new ArrayList();
- Class clazz = null ;
- try {
- clazz = Class.forName(className);
- } catch (ClassNotFoundException e) {
- throw new RuntimeException("类名有问题,请重新输入");
-
- }
- String modifierName = Modifier.toString(clazz.getModifiers());
- StringBuilder sb = new StringBuilder();
- if(modifierName != null && modifierName.length()>0){
- sb.append(modifierName);
- }
-
- sb.append(" "+clazz.getName()+"{");
- sb.append(System.getProperty("line.separator"));
- printConstructors(clazz,sb);
- printMethods(clazz,sb);
- printFields(clazz,sb);
-
- sb.append(System.getProperty("line.separator"));
- sb.append("}");
- System.out.println(sb.toString());
- }
-
-
-
-
-
-
- private static void printFields(Class clazz, StringBuilder sb) {
- sb.append(System.getProperty("line.separator"));
- sb.append("\t");
- Field[] fields = clazz.getFields();
- for(Field field:fields){
- sb.append(Modifier.toString(field.getModifiers()));
- sb.append(field.getName());
- sb.append(System.getProperty("line.separator"));
- sb.append("\t");
- }
- }
-
-
-
-
-
-
- private static void printMethods(Class clazz, StringBuilder sb) {
- sb.append(System.getProperty("line.separator"));
- sb.append("\t");
- Method[] methods = clazz.getMethods();
- for(Method method:methods){
- Class[] paraClasses = method.getParameterTypes();
- sb.append(Modifier.toString(method.getModifiers()));
- sb.append(" "+method.getName()+"(");
- for(Class paraClass: paraClasses){
- sb.append(paraClass.getName()+",");
- }
- if(null != paraClasses && 0 != paraClasses.length){
- sb.deleteCharAt(sb.length()-1);
- }
- sb.append(")");
- sb.append(System.getProperty("line.separator"));
- sb.append("\t");
- }
- }
-
-
-
-
-
-
- private static void printConstructors(Class clazz,StringBuilder sb) {
- sb.append("\t");
- Constructor[] cons = clazz.getConstructors();
- for(Constructor con : cons){
- String conModifier = Modifier.toString(con.getModifiers());
- sb.append(conModifier);
- sb.append(" "+con.getName()+"(");
- Class[] types = con.getParameterTypes();
- for(Class type:types){
- sb.append(type.getName()+",");
- }
- if(null!=types && 0 !=types.length){
- sb.deleteCharAt(sb.length()-1);
- }
- sb.append(")");
- sb.append(System.getProperty("line.separator"));
- sb.append("\t");
- }
- }
-
-
-
-
-
- private static void applyReflectChangeObjValDemo() {
- ReflectDemo rd = new ReflectDemo();
-
- Method m1 = null ;
- try{
- Class lc = rd.getClass();
- m1 = lc.getMethod("setName", String.class);
- Boolean b = (Boolean)m1.invoke(rd, "four");
- System.out.println("---------------:"+rd.getName());
- rd.setSize(21);
- m1 = lc.getMethod("getSize");
- Integer size = (Integer)m1.invoke(rd);
- System.out.println("Size大小::"+size);
-
- m1 = lc.getMethod("getPI");
- Double d = (Double)m1.invoke(null);
- System.out.println("PI的值为::"+d.doubleValue());
-
- Field f = lc.getDeclaredField("pos");
- f.setAccessible(true);
- int value = 88;
- f.set(rd, value);
- System.out.println("------pos为---"+rd.getPos());
- f.set(rd, size);
- System.out.println("-----恢复pos后为---"+rd.getPos());
-
- rd.setName("sdfasdf");
- f = lc.getField("name");
- System.out.println("------------name的值为-------::"+f.get(rd));
- f.set(rd, "zhangsan");
- System.out.println("------------name的值为-------::"+f.get(rd));
-
- }catch(Exception e){
- e.printStackTrace();
- System.out.println("异常了------------------------------------------");
- }
-
- }
-
-
-
-
-
- public static void printIntArray(int[] args){
- System.out.println("------printIntArray invorked---------");
- for(int arg:args){
- System.out.println(arg);
- }
-
- }
-
- public static void printStringArray(String[] args){
- System.out.println("------printStringArray invorked---------");
- for(String arg:args){
- System.out.println(arg);
- }
-
- }
-
- public static void printIntegerArray(Integer... args){
- System.out.println("------printIntegerArray invorked---------");
- for(Integer arg:args){
- System.out.println(arg);
- }
- }
-
- public int getPos() {
- return pos;
- }
-
- public void setPos(int pos) {
- this.pos = pos;
- }
-
- public String getName() {
- return name;
- }
-
- public void setName(String name) {
- this.name = name;
- }
-
- public int getSize() {
- return size;
- }
-
- public void setSize(int size) {
- this.size = size;
- }
-
- public ArrayList getAlist() {
- return alist;
- }
-
- public void setAlist(ArrayList alist) {
- this.alist = alist;
- }
-
- }
需要注意:反射在调用带数组参数的方法时,一定要注意invork方法调用的情况,因为传入invork方法是一个数组的话,编译器会采用JDK1.4折方法特性将数组拆包,数组中每个元素将作为一个参数传入到相应方法中。这样肯定会与之前的getMethod中的数组.class有冲突,会报java.lang.IllegalArgumentException: wrong number of arguments 参数数量不对了。
为了解决此问题,有两种方法,
一种是不让JDK1.4插手,那么就可将数组前面强转成Object,这样编译器会使用JDK1.5的,不会将数组拆包。如:m1.invoke(rd, (Object)new String[]{"abc","bcd"});
另一种方法是,还是让JDK1.4编,那么外面再用一个数组包起,这个数组。这样JDK1.4遇到这个数组的数组,拆包后还是一样数组正好与getMethod中是一致的。如m1.invoke(rd, new Object[]{new String[]{"abc","bcd"}});
五、内省
内省对应的英文单词为IntroSpector,它主要用于对JavaBean进行操作,JavaBean是一种特殊的Java类,其中的某些方法符合某种命名规则,如果一个Java类中的一些方法符合某种命名规则,则可以把它当作JavaBean来使用。通常的JavaBean是满足有setter与getter方法,且方法名去掉set前缀后,若第二个字母是小写,则属性名为第一个字母小写后的方法名后缀如setXxx 则 属性名为xxx。而若第二个字母也是小写,则属性名是去掉前缀后所有的后缀,如setCPU,则CPU为属性名。这点在后期学习的el表代式都有应用。
操作JavaBean另一个方法的工具包是BeanUtils,它需要loggin包的支持。
BeanUtils 官方下载地址:http://commons.apache.org/beanutils/
Logging 官方下载地址:http://commons.apache.org/logging/
具体示例代码:
- package com.enhance;
-
- import java.beans.BeanInfo;
- import java.beans.IntrospectionException;
- import java.beans.Introspector;
- import java.beans.PropertyDescriptor;
- import java.lang.reflect.InvocationTargetException;
- import java.lang.reflect.Method;
- import java.util.ArrayList;
- import java.util.Arrays;
- import java.util.HashMap;
- import java.util.Map;
-
- import org.apache.commons.beanutils.BeanUtils;
- import org.apache.commons.beanutils.PropertyUtils;
-
-
-
-
-
-
-
-
- public class IntroSpectorDemo {
-
- public static void main(String[] args){
-
- ReflectDemo rfd = new ReflectDemo();
- rfd.setName("zhangsan");
- rfd.setPos(0);
- rfd.setSize(3);
- ArrayList al = new ArrayList();
- al.add("abc");
- al.add("bcd");
- rfd.setAlist(al);
-
- propertyDescriptorDemo(rfd);
-
-
- beanInfoDemo(rfd);
- beanUtilsDemo(rfd);
- }
-
- private static void beanUtilsDemo(ReflectDemo rfd) {
- String name = null;
- PropertyDescriptor pd = null ;
- try{
-
- name = BeanUtils.getProperty(rfd, "name");
- System.out.println(name);
-
- BeanUtils.setProperty(rfd, "name", "wangwu");
- System.out.println(rfd.getName());
-
- name = BeanUtils.getProperty(rfd, "alist");
- System.out.println(name);
-
-
- String[] names = BeanUtils.getArrayProperty(rfd, "alist");
- System.out.println("------alist-------::"+Arrays.toString(names));
-
-
- pd = new PropertyDescriptor("alist",rfd.getClass());
- Class propClazz = pd.getPropertyType();
- System.out.println("属性的类型为::"+propClazz.getName());
-
- Method readMethod = pd.getReadMethod();
- Object obj = readMethod.invoke(rfd);
- System.out.println(obj.getClass().isArray());
- ArrayList alist = (ArrayList)obj;
- System.out.println(alist);
-
- System.out.println("----------------隔开,下面测试用Map的方式来玩转BeanUtils---------------");
- Map map = new HashMap();
- map.put("size", 88);
- map.put("age", 28);
-
-
- String sizeStr = BeanUtils.getProperty(map, "size");
- String ageStr = BeanUtils.getProperty(map, "age");
- System.out.println("[size="+sizeStr+",age="+ageStr+"]");
-
-
- Integer age = (Integer)PropertyUtils.getProperty(map, "age");
- System.out.println(age);
-
- }catch(Exception e){
- e.printStackTrace();
- }
- }
-
- private static void beanInfoDemo(ReflectDemo rfd) {
- BeanInfo bi = null;
- String propName = "name";
- try {
- bi = Introspector.getBeanInfo(rfd.getClass());
- PropertyDescriptor[] pds = bi.getPropertyDescriptors();
- for(PropertyDescriptor pd:pds){
- if(propName.equals(pd.getName())){
- System.out.println("beaninfo得到PropertyDescriptors数组后,再迭代PropertyDescriptor,得到name的值::"+pd.getReadMethod().invoke(rfd));
- }
- }
-
- } catch (Exception e) {
- e.printStackTrace();
- }
-
-
- }
-
- private static void propertyDescriptorDemo(ReflectDemo rfd) {
-
-
- PropertyDescriptor pd = null ;
-
- try {
- pd = new PropertyDescriptor("name",rfd.getClass());
- Class propClazz = pd.getPropertyType();
- System.out.println("属性的类型为::"+propClazz.getName());
-
- Method readMethod = pd.getReadMethod();
- Method writeMethod = pd.getWriteMethod();
-
-
- System.out.println("调用读方法,读name的值为::"+readMethod.invoke(rfd));
-
-
- writeMethod.invoke(rfd, "lisi");
- System.out.println("调用写方法,将name的值改变后为::"+rfd.getName());
-
- } catch (IntrospectionException e) {
- e.printStackTrace();
- }catch (IllegalArgumentException e) {
- e.printStackTrace();
- } catch (IllegalAccessException e) {
- e.printStackTrace();
- } catch (InvocationTargetException e) {
- e.printStackTrace();
- }
- }
-
- }
转自:http://blog.csdn.net/luqin1988/article/details/8019374