已同步更新至我的blog:http://dxjia.cn/2015/08/java-reflect/ html
引用baidubaike上对JAVA反射的说明,以下:JAVA反射机制是在运行状态中,对于任意一个类,都可以知道这个类的全部属性和方法(成员变量和函数);对于任意一个对象,都可以调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。java
而可以使JAVA有这样的能力,归根结底是因为JVM,而小一点说,是由于有Class对象的存在,我在上一篇文章中有讲解JAVA的Class对象,它是在类加载完后,每一个类都会产生的一个实例,而其内部详细描述了这个类的状况,因此咱们能够经过这个Class对象来获得任何有关这个类的细节,不只仅能了解这个类,java还提供了方法来动态执行这个类里的方法或修改为员变量的值。安全
反射机制的优势与缺点:(参考:【Java反射机制】)函数
为何要用反射机制?直接建立对象不就能够了吗,这就涉及到了动态与静态的概念,
静态编译:在编译时肯定类型,绑定对象,即经过。
动态编译:运行时肯定类型,绑定对象。动态编译最大限度发挥了java的灵活性,体现了多态的应用,有以下降类之间的藕合性。
一句话,反射机制的优势就是能够实现动态建立对象和编译,体现出很大的灵活性,特别是在J2EE的开发中它的灵活性就表现的十分明显。好比,一个大型的软件,不可能一次就把把它设计的很完美,当这个程序编
译后,发布了,当发现须要更新某些功能时,咱们不可能要用户把之前的卸载,再从新安装新的版本,假如这样的话,这个软件确定是没有多少人用的。采用静态的话,须要把整个程序从新编译一次才能够实现功能
的更新,而采用反射机制的话,它就能够不用卸载,只须要在运行时才动态的建立和编译,就能够实现该功 能。
它的缺点是对性能有影响。使用反射基本上是一种解释操做,咱们能够告诉JVM,咱们但愿作什么而且它知足咱们的要求。这类操做老是慢于只直接执行相同的操做。 性能
下面是个人练习程序:测试
在目录下新建com\dxjia\sample路径,而后在sample下新建一个UserBean.java的文件,这将是咱们用来进行反射的类。代码以下:spa
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("\n--------------获取类的全部信息----------------------\n"); 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(")\n"); 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("\n----------------测试使用----------------------\n"); 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,切换到该目录下,执行code
1 javac com\dxjia\sample\UserBean.java 2 javac -encoding UTF-8 -Xlint:unchecked Test.java
编译经过后,执行:htm
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