已同步更新至个人blog:http://dxjia.cn/2015/08/java-reflect/
引用baidubaike上对JAVA反射的说明,如下:JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法(成员变量和函数);对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。
而能够使JAVA有这样的能力,归根结底是由于JVM,而小一点说,是因为有Class对象的存在,我在上一篇文章中有讲解JAVA的Class对象,它是在类加载完后,每个类都会产生的一个实例,而其内部详细描述了这个类的情况,所以我们可以通过这个Class对象来得到任何有关这个类的细节,不仅仅能了解这个类,java还提供了方法来动态执行这个类里的方法或修改成员变量的值。
反射机制的优点与缺点:(参考:【Java反射机制】)
为什么要用反射机制?直接创建对象不就可以了吗,这就涉及到了动态与静态的概念,
静态编译:在编译时确定类型,绑定对象,即通过。
动态编译:运行时确定类型,绑定对象。动态编译最大限度发挥了java的灵活性,体现了多态的应用,有以降低类之间的藕合性。
一句话,反射机制的优点就是可以实现动态创建对象和编译,体现出很大的灵活性,特别是在J2EE的开发中它的灵活性就表现的十分明显。比如,一个大型的软件,不可能一次就把把它设计的很完美,当这个程序编
译后,发布了,当发现需要更新某些功能时,我们不可能要用户把以前的卸载,再重新安装新的版本,假如这样的话,这个软件肯定是没有多少人用的。采用静态的话,需要把整个程序重新编译一次才可以实现功能
的更新,而采用反射机制的话,它就可以不用卸载,只需要在运行时才动态的创建和编译,就可以实现该功 能。
它的缺点是对性能有影响。使用反射基本上是一种解释操作,我们可以告诉JVM,我们希望做什么并且它满足我们的要求。这类操作总是慢于只直接执行相同的操作。
下面是我的练习程序:
在目录下新建comdxjiasample路径,然后在sample下新建一个UserBean.java的文件,这将是我们用来进行反射的类。代码如下:
1 package com.dxjia.sample; 2 3 public class UserBean { 4 private String mName; 5 private int mAge; 6 private String mVersion = "1.0"; 7 8 public UserBean() { 9 System.out.println(" UserBean Constructor1 called!"); 10 } 11 12 public UserBean(String name, int age) { 13 System.out.println(" UserBean Constructor2 called!"); 14 init(name, age); 15 } 16 17 public void setName(String name) { 18 mName = name; 19 System.out.println(" UserBean setName() done"); 20 } 21 22 public String getName() { 23 return mName; 24 } 25 26 public void setAge(int age) { 27 mAge = age; 28 System.out.println(" UserBean setAge() done"); 29 } 30 31 public int getAge() { 32 return mAge; 33 } 34 35 private void init(String name, int age) { 36 mName = name; 37 mAge = age; 38 } 39 40 public void printVersion() { 41 System.out.println(" UserBean VERSION: " + mVersion); 42 } 43 44 public void printName() { 45 System.out.println(" UserBean mName [" + mName + "]"); 46 } 47 48 public void printAge() { 49 System.out.println(" UserBean mAge [" + mAge + "]"); 50 } 51 52 private void printUserInfo() { 53 System.out.println(" UserBean mName [" + mName + "] " + "mAge [" + mAge + "]"); 54 } 55 }
然后在根目录下新建Test.java文件,这里实现我们的测试程序,代码如下【注意注释】:
1 import java.lang.*; 2 import java.lang.reflect.*; 3 4 public class Test { 5 6 public static void main(String[] args) { 7 8 try { 9 Class c = Class.forName("com.dxjia.sample.UserBean"); 10 if (null == c) { 11 System.out.println("can`t load class!"); 12 return; 13 } 14 15 System.out.println(" --------------获取类的所有信息---------------------- "); 16 17 // 获取类的修饰符,public private... 18 int mod = c.getModifiers(); 19 String modifier = Modifier.toString(mod); 20 System.out.println("modifier : " + modifier); 21 22 // 获取父类 23 Class superClass = c.getSuperclass(); 24 String superClassName = superClass.getName(); 25 System.out.println("superClassName : " + superClassName); 26 27 // 获取implements的接口 28 Class[] interfaces = c.getInterfaces(); 29 if (interfaces.length != 0) { 30 for (Class cl : interfaces) { 31 System.out.println("interfacesName : " + cl.getName()); 32 } 33 } else { 34 System.out.println("interfacesName : "); 35 } 36 37 // 获取所有的成员变量 38 Field[] fields = c.getDeclaredFields(); 39 if (fields.length != 0) { 40 System.out.println("fields : "); 41 for (Field field : fields) { 42 modifier = Modifier.toString(field.getModifiers()); 43 Class type = field.getType(); 44 String name = field.getName(); 45 if (type.isArray()) { 46 String arrType = type.getComponentType().getName() + "[]"; 47 System.out.println(" " + modifier + " " + arrType + " " + name + ";"); 48 } else { 49 System.out.println(" " + modifier + " " + type + " " + name + ";"); 50 } 51 } 52 } else { 53 System.out.println("fields : "); 54 } 55 56 // 获取所有的构造函数 57 Constructor[] constructors = c.getDeclaredConstructors(); 58 if(constructors.length != 0) { 59 System.out.println("constructors : "); 60 for (Constructor constructor : constructors) { 61 // 构造方法名 62 String name = constructor.getName(); 63 // 获取访问修饰符,public private protected 64 modifier = Modifier.toString(constructor.getModifiers()); 65 System.out.print(" " + modifier +" " + name + "("); 66 // 获取构造方法中的所有参数, paramTypes.length为0,说明是无参构造函数 67 Class[] paramTypes = constructor.getParameterTypes(); 68 for (int i = 0; i < paramTypes.length; i++) { 69 if (i > 0) { 70 System.out.print(", "); 71 } 72 if (paramTypes[i].isArray()) { 73 System.out.print(paramTypes[i].getComponentType().getName()+"[]"); 74 } else { 75 System.out.print(paramTypes[i].getName()); 76 } 77 } 78 System.out.print(") "); 79 } 80 } else { 81 System.out.println("constructors : "); 82 } 83 84 // 获取所有的成员函数 85 Method[] methods = c.getDeclaredMethods(); 86 if(methods.length != 0) { 87 System.out.println("methods : "); 88 for (Method method: methods) { 89 // 获取方法的描述符,private public protected... 90 modifier = Modifier.toString(method.getModifiers()); 91 // 获取方法的返回类型 92 Class returnType = method.getReturnType(); 93 if (returnType.isArray()) { 94 String arrType = returnType.getComponentType().getName()+"[]"; 95 System.out.print(" " + modifier + " " + arrType + " " + method.getName() + "("); 96 } else { 97 System.out.print(" " + modifier + " " + returnType.getName() + " " + method.getName() + "("); 98 } 99 // 获取所有的参数信息 100 Class[] paramTypes = method.getParameterTypes(); 101 for (int i = 0; i < paramTypes.length; i++) { 102 if (i > 0) { 103 System.out.print(","); 104 } 105 if (paramTypes[i].isArray()) { 106 System.out.println(paramTypes[i].getComponentType().getName()+"[]"); 107 } else { 108 System.out.print(paramTypes[i].getName()); 109 } 110 } 111 System.out.println(");"); 112 } 113 } else { 114 System.out.println("methods : "); 115 } 116 117 System.out.println(" ----------------测试使用---------------------- "); 118 119 /** 120 * 测试反射,调用函数,变量赋值等 121 * 反射的使用一般都会先像上面这样打印出来,进行一个分析之后, 122 * 再编写类似下面的代码来反射调用类的函数,也就是自己先通过上面的方式来了解这个类, 123 * 然后再hard code反射使用这个类中对自己有用的函数来达到目的。当然,我们比较了解那个类了,只是环境中没有公开,所以我们需要反射 124 */ 125 // 首先可以实例化对象,因为万物都继承自Object 126 // 所以这里用Object来声明定义对象,不影响使用 127 // 直接使用Class.newInstance()函数,是调用的类的无参构造函数 128 System.out.println("调用无参构造函数"); 129 Object bean1 = c.newInstance(); 130 131 // 如果要调用有参构造函数,那就要使用下面的方式 132 Class[] paramTypes = {String.class, int.class}; 133 Constructor con = c.getConstructor(String.class, int.class); 134 // 使用 135 System.out.println("调用有参构造函数"); 136 Object bean2 = con.newInstance("小明", 16); 137 138 // 调用bean2 public 函数 printVersion() 139 System.out.println("执行public printVersion()"); 140 Method method1 = c.getDeclaredMethod("printVersion"); 141 method1.invoke(bean2); 142 143 // 调用bean2 private函数 printUserInfo() 144 System.out.println("执行public printUserInfo()"); 145 Method method2 = c.getDeclaredMethod("printUserInfo"); 146 // 因为printUserInfo是private方法,所以需要加上这句来避免安全检查,这样才可以调用私有方法 147 method2.setAccessible(true); 148 // 执行 149 method2.invoke(bean2); 150 151 // 调用有参数的函数 setName() setAge() 152 System.out.println("调用有参数函数设置新name和age"); 153 Method method3 = c.getDeclaredMethod("setName", String.class); 154 method3.invoke(bean2, "张三"); 155 Method method4 = c.getDeclaredMethod("setAge", int.class); 156 method4.invoke(bean2, 25); 157 158 // 调用 printUserInfo 将新值打印出来 159 System.out.println("打印新值"); 160 method2.invoke(bean2); 161 162 // 直接操作成员变量,给私有成员变量赋值,记得加setAccessible(true); 163 Field field = c.getDeclaredField("mVersion"); 164 field.setAccessible(true); 165 String oldVersion = (String) field.get(bean2); 166 System.out.println("直接获取私有变量mVersion的值,并打印:" + oldVersion); 167 System.out.println("直接将私有成员变量mVersion赋值2.0"); 168 field.set(bean2, "2.0"); 169 // 调用printVersion()打印新值 170 System.out.println("打印新值"); 171 method1.invoke(bean2); 172 } catch (ClassNotFoundException e) { 173 System.out.println("exception: " + e.toString()); 174 } catch (InstantiationException e) { 175 System.out.println("exception: " + e.toString()); 176 } catch (IllegalAccessException e) { 177 System.out.println("exception: " + e.toString()); 178 } catch (NoSuchMethodException e) { 179 System.out.println("exception: " + e.toString()); 180 } catch (InvocationTargetException e) { 181 System.out.println("exception: " + e.toString()); 182 } catch (NoSuchFieldException e) { 183 System.out.println("exception: " + e.toString()); 184 } 185 } 186 187 }
打开cmd,切换到该目录下,执行
1 javac comdxjiasampleUserBean.java 2 javac -encoding UTF-8 -Xlint:unchecked Test.java
编译通过后,执行:
1 java Test
打印如下:
--------------获取类的所有信息---------------------- modifier : public superClassName : java.lang.Object interfacesName : fields : private class java.lang.String mName; private int mAge; private class java.lang.String mVersion; constructors : public com.dxjia.sample.UserBean() public com.dxjia.sample.UserBean(java.lang.String, int) methods : public int getAge(); public void printName(); public void printAge(); public java.lang.String getName(); private void init(java.lang.String,int); public void setName(java.lang.String); public void setAge(int); public void printVersion(); private void printUserInfo(); ----------------测试使用---------------------- 调用无参构造函数 UserBean Constructor1 called! 调用有参构造函数 UserBean Constructor2 called! 执行public printVersion() UserBean VERSION: 1.0 执行public printUserInfo() UserBean mName [小明] mAge [16] 调用有参数函数设置新name和age UserBean setName() done UserBean setAge() done 打印新值 UserBean mName [张三] mAge [25] 直接获取私有变量mVersion的值,并打印:1.0 直接将私有成员变量mVersion赋值2.0 打印新值 UserBean VERSION: 2.0