JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法;这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。
通俗地说,反射机制就是可以把一个类,类的成员(函数,属性),当成一个对象来操作,希望读者能理解,也就是说,类,类的成员,我们在运行的时候还可以动态地去操作他们.
Java反射机制主要提供了以下功能: 在运行时判断任意一个对象所属的类;在运行时构造任意一个类的对象;在运行时判断任意一个类所具有的成员变量和方法;在运行时调用任意一个对象的方法;生成动态代理。
如果你使用Java,那么你应该知道Java中有一个Class类。Class类本身表示Java对象的类型,我们可以通过一个Object(子)对象的getClass方法取得一个对象的类型,此函数返回的就是一个Class类。当然,获得Class对象的方法有许多,但是没有一种方法是通过Class的构造函数来生成Class对象的。
也许你从来没有使用过Class类,也许你曾以为这是一个没什么用处的东西。不管你以前怎么认为,Class类是整个Java反射机制的源头。一切关于Java反射的故事,都从Class类开始。
因此,要想使用Java反射,我们首先得到Class类的对象。下表列出了几种得到Class类的方法,以供大家参考。
Class object 诞生管道 |
示例 |
运用getClass() 注:每个class 都有此函数 |
String str = "abc"; Class c1 = str.getClass(); |
运用 Class.getSuperclass() |
Button b = new Button(); Class c1 = b.getClass(); Class c2 = c1.getSuperclass(); |
运用static method Class.forName() (最常被使用) |
Class c1 = Class.forName ("java.lang.String"); Class c2 = Class.forName ("java.awt.Button"); Class c3 = Class.forName ("java.util.LinkedList$Entry"); Class c4 = Class.forName ("I"); Class c5 = Class.forName ("[I"); |
运用 .class 语法 |
Class c1 = String.class; Class c2 = java.awt.Button.class; Class c3 = Main.InnerClass.class; Class c4 = int.class; Class c5 = int[].class; |
运用 primitive wrapper classes 的TYPE 语法 |
Class c1 = Boolean.TYPE; Class c2 = Byte.TYPE; Class c3 = Character.TYPE; Class c4 = Short.TYPE; Class c5 = Integer.TYPE; Class c6 = Long.TYPE; Class c7 = Float.TYPE; Class c8 = Double.TYPE; Class c9 = Void.TYPE; |
在我们得到一个类的Class类对象之后,Java反射机制就可以大施拳脚了。首先让我们来了解下如何获取关于某一个类的一些基本信息。
Java class 内部模块 |
Java class 内部模块说明 |
相应之Reflection API,多半为Class methods。 |
返回值类型(return type) |
package |
class隶属哪个package |
getPackage() |
Package |
import |
class导入哪些classes |
无直接对应之API。可间接获取。 |
|
modifier |
class(或methods, fields)的属性 |
int getModifiers() Modifier.toString (int) Modifier.isInterface(int) |
int String bool |
class name or interface name |
class/interface |
名称getName() |
String |
type parameters |
参数化类型的名称 |
getTypeParameters() |
TypeVariable <Class>[] |
base class |
base class(只可能一个) |
getSuperClass() |
Class |
implemented interfaces |
实现有哪些interfaces |
getInterfaces() |
Class[] |
inner classes |
内部classes |
getDeclaredClasses() |
Class[] |
outer class |
如果我们观察的class 本身是inner classes,那么相对它就会有个outer class。 |
getDeclaringClass() |
Class |
上表中,列出了一些Java class内部信息的获取方式。所采用的方法几乎都是调用Class对象的成员方法(由此你就可以了解到Class类的用处了吧)。当然,表中所列出的信息并不是全部,有很大一部分没有列出,你可以通过查阅Java文档得到更全面的了解。另外,下面将重点介绍一下类的构造函数、域和成员方法的获取方式。
如果要对一个类的信息重要性进行排名的话,那么这三个信息理应获得前三的名次。它们分别是:构造函数、成员函数、成员变量。
也许你不同意我的排名,没关系。对于Java反射来说,这三个信息与之前介绍的基本信息相比较而言,有着本质的区别。那就是,之前的信息仅仅是只读的,而这三个信息可以在运行时被调用(构造函数和成员函数)或者被修改(成员变量)。所以,我想无可否认,至少站在Java反射机制的立场来说,这三者是最重要的信息。
下面,让我们分别了解一下这三个重要信息的获取方式。另外,我们将在后面的章节,详细介绍他们的调用方式或者修改方式。
如果我们将Java对象视为一个二进制的生活在内存中生命体的话,那么构造函数无疑可以类比为Java对象生命体的诞生过程。我们在构造函数调用时为对象分配内存空间,初始化一些属性,于是一个新的生命诞生了。
Java是纯面向对象的语言,Java中几乎所有的一切都是类的对象,因此可想而知构造函数的重要性。
Java反射机制能够得到构造函数信息实在应该是一件令人惊喜的事情。正因为此,反射机制实质上才拥有了孵化生命的能力。换句话言之,我们可以通过反射机制,动态地创建新的对象。
获取构造函数的方法有以下几个:
Constructor getConstructor(Class[] params)
Constructor[] getConstructors()
Constructor getDeclaredConstructor(Class[] params)
Constructor[] getDeclaredConstructors()
我们有两种方式对这四个函数分组。
首先可以由构造函数的确定性进行分类。我们知道,一个类实际上可以拥有很多个构造函数。那么我们获取的构造函数是哪个呢?我们可以根据构造函数的参数标签对构造函数进行明确的区分,因此,如果我们在Java反射时指定构造函数的参数,那么我们就能确定地返回我们需要的那个“唯一”的构造函数。getConstructor(Class[] params) 和getDeclaredConstructor(Class[] params)正是这种确定唯一性的方式。但是,如果我们不清楚每个构造函数的参数表,或者我们出于某种目的需要获取所有的构造函数的信息,那么我们就不需要明确指定参数表,而这时返回的就应该是构造函数数组,因为构造函数很可能不止一个。getConstructors()和getDeclaredConstructors()就是这种方式。
另外,我们还可以通过构造函数的访问权限进行分类。在设计类的时候,我们往往有一些构造函数需要声明为“private”、“protect”或者“default”,目的是为了不让外部的类调用此构造函数生成对象。于是,基于访问权限的不同,我们可以将构造函数分为public和非public两种。
getConstructor(Class[] params) 和getConstructors()仅仅可以获取到public的构造函数,而getDeclaredConstructor(Class[] params) 和getDeclaredConstructors()则能获取所有(包括public和非public)的构造函数。
如果构造函数类比为对象的诞生过程的话,成员函数无疑可以类比为对象的生命行为过程。成员函数的调用执行才是绝大多数对象存在的证据和意义。Java反射机制允许获取成员函数(或者说成员方法)的信息,也就是说,反射机制能够帮助对象践行生命意义。通俗地说,Java反射能使对象完成其相应的功能。
和获取构造函数的方法类似,获取成员函数的方法有以下一些:
Method getMethod(String name, Class[] params)
Method[] getMethods()
Method getDeclaredMethod(String name, Class[] params)
Method[] getDeclaredMethods()
其中需要注意,String name参数,需要写入方法名。关于访问权限和确定性的问题,和构造函数基本一致。
成员变量,我们经常叫做一个对象的域。从内存的角度来说,构造函数和成员函数都仅仅是Java对象的行为或过程,而成员变量则是真正构成对象本身的细胞和血肉。简单的说,就是成员变量占用的空间之和几乎就是对象占用的所有内存空间。
获取成员变量的方法与上面两种方法类似,具体如下:
Field getField(String name)
Field[] getFields()
Field getDeclaredField(String name)
Field[] getDeclaredFields()
其中,String name参数,需要写入变量名。关于访问权限和确定性的问题,与前面两例基本一致。
1.package cn.lee.demo; 2. 3.import java.lang.reflect.Constructor; 4.import java.lang.reflect.Field; 5.import java.lang.reflect.InvocationTargetException; 6.import java.lang.reflect.Method; 7.import java.lang.reflect.Modifier; 8.import java.lang.reflect.TypeVariable; 9. 10.public class Main { 11. /** 12. * 为了看清楚Java反射部分代码,所有异常我都最后抛出来给虚拟机处理! 13. * @param args 14. * @throws ClassNotFoundException 15. * @throws InstantiationException 16. * @throws IllegalAccessException 17. * @throws InvocationTargetException 18. * @throws IllegalArgumentException 19. * @throws NoSuchFieldException 20. * @throws SecurityException 21. * @throws NoSuchMethodException 22. */ 23. public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException, SecurityException, NoSuchFieldException, NoSuchMethodException { 24. // TODO Auto-generated method stub 25. 26. //Demo1. 通过Java反射机制得到类的包名和类名 27. Demo1(); 28. System.out.println("==============================================="); 29. 30. //Demo2. 验证所有的类都是Class类的实例对象 31. Demo2(); 32. System.out.println("==============================================="); 33. 34. //Demo3. 通过Java反射机制,用Class 创建类对象[这也就是反射存在的意义所在],无参构造 35. Demo3(); 36. System.out.println("==============================================="); 37. 38. //Demo4: 通过Java反射机制得到一个类的构造函数,并实现构造带参实例对象 39. Demo4(); 40. System.out.println("==============================================="); 41. 42. //Demo5: 通过Java反射机制操作成员变量, set 和 get 43. Demo5(); 44. System.out.println("==============================================="); 45. 46. //Demo6: 通过Java反射机制得到类的一些属性: 继承的接口,父类,函数信息,成员信息,类型等 47. Demo6(); 48. System.out.println("==============================================="); 49. 50. //Demo7: 通过Java反射机制调用类中方法 51. Demo7(); 52. System.out.println("==============================================="); 53. 54. //Demo8: 通过Java反射机制获得类加载器 55. Demo8(); 56. System.out.println("==============================================="); 57. 58. } 59. 60. /** 61. * Demo1: 通过Java反射机制得到类的包名和类名 62. */ 63. public static void Demo1() 64. { 65. Person person = new Person(); 66. System.out.println("Demo1: 包名: " + 67. person.getClass().getPackage().getName() + "," 68. + "完整类名: " + person.getClass().getName()); 69. } 70. 71. /** 72. * Demo2: 验证所有的类都是Class类的实例对象 73. * @throws ClassNotFoundException 74. */ 75. public static void Demo2() throws ClassNotFoundException 76. { 77. //定义两个类型都未知的Class , 设置初值为null, 看看如何给它们赋值成Person类 78. Class<?> class1 = null; 79. Class<?> class2 = null; 80. 81. //写法1, 可能抛出 ClassNotFoundException [多用这个写法] 82. class1 = Class.forName("cn.lee.demo.Person"); 83. System.out.println("Demo2:(写法1) 包名: " + class1.getPackage().getName() + "," 84. + "完整类名: " + class1.getName()); 85. 86. //写法2 87. class2 = Person.class; 88. System.out.println("Demo2:(写法2) 包名: " + class2.getPackage().getName() + "," 89. + "完整类名: " + class2.getName()); 90. } 91. 92. /** 93. * Demo3: 通过Java反射机制,用Class 创建类对象[这也就是反射存在的意义所在] 94. * @throws ClassNotFoundException 95. * @throws IllegalAccessException 96. * @throws InstantiationException 97. */ 98. public static void Demo3() throws ClassNotFoundException, InstantiationException, IllegalAccessException 99. { 100. Class<?> class1 = null; 101. class1 = Class.forName("cn.lee.demo.Person"); 102. //由于这里不能带参数,所以你要实例化的这个类Person,一定要有无参构造函数哈~ 103. Person person = (Person) class1.newInstance(); 104. person.setAge(20); 105. person.setName("LeeFeng"); 106. System.out.println("Demo3: " + person.getName() + " : " + person.getAge()); 107. } 108. 109. /** 110. * Demo4: 通过Java反射机制得到一个类的构造函数,并实现创建带参实例对象 111. * @throws ClassNotFoundException 112. * @throws InvocationTargetException 113. * @throws IllegalAccessException 114. * @throws InstantiationException 115. * @throws IllegalArgumentException 116. */ 117. public static void Demo4() throws ClassNotFoundException, IllegalArgumentException, InstantiationException, IllegalAccessException, InvocationTargetException 118. { 119. Class<?> class1 = null; 120. Person person1 = null; 121. Person person2 = null; 122. 123. class1 = Class.forName("cn.lee.demo.Person"); 124. //得到一系列构造函数集合 125. Constructor<?>[] constructors = class1.getConstructors(); 126. 127. person1 = (Person) constructors[0].newInstance(); 128. person1.setAge(30); 129. person1.setName("leeFeng"); 130. 131. person2 = (Person) constructors[1].newInstance(20,"leeFeng"); 132. 133. System.out.println("Demo4: " + person1.getName() + " : " + person1.getAge() 134. + " , " + person2.getName() + " : " + person2.getAge() 135. ); 136. 137. } 138. 139. /** 140. * Demo5: 通过Java反射机制操作成员变量, set 和 get 141. * 142. * @throws IllegalAccessException 143. * @throws IllegalArgumentException 144. * @throws NoSuchFieldException 145. * @throws SecurityException 146. * @throws InstantiationException 147. * @throws ClassNotFoundException 148. */ 149. public static void Demo5() throws IllegalArgumentException, IllegalAccessException, SecurityException, NoSuchFieldException, InstantiationException, ClassNotFoundException 150. { 151. Class<?> class1 = null; 152. class1 = Class.forName("cn.lee.demo.Person"); 153. Object obj = class1.newInstance(); 154. 155. Field personNameField = class1.getDeclaredField("name"); 156. personNameField.setAccessible(true); 157. personNameField.set(obj, "胖虎先森"); 158. 159. 160. System.out.println("Demo5: 修改属性之后得到属性变量的值:" + personNameField.get(obj)); 161. 162. } 163. 164. 165. /** 166. * Demo6: 通过Java反射机制得到类的一些属性: 继承的接口,父类,函数信息,成员信息,类型等 167. * @throws ClassNotFoundException 168. */ 169. public static void Demo6() throws ClassNotFoundException 170. { 171. Class<?> class1 = null; 172. class1 = Class.forName("cn.lee.demo.SuperMan"); 173. 174. //取得父类名称 175. Class<?> superClass = class1.getSuperclass(); 176. System.out.println("Demo6: SuperMan类的父类名: " + superClass.getName()); 177. 178. System.out.println("==============================================="); 179. 180. 181. Field[] fields = class1.getDeclaredFields(); 182. for (int i = 0; i < fields.length; i++) { 183. System.out.println("类中的成员: " + fields[i]); 184. } 185. System.out.println("==============================================="); 186. 187. 188. //取得类方法 189. Method[] methods = class1.getDeclaredMethods(); 190. for (int i = 0; i < methods.length; i++) { 191. System.out.println("Demo6,取得SuperMan类的方法:"); 192. System.out.println("函数名:" + methods[i].getName()); 193. System.out.println("函数返回类型:" + methods[i].getReturnType()); 194. System.out.println("函数访问修饰符:" + Modifier.toString(methods[i].getModifiers())); 195. System.out.println("函数代码写法: " + methods[i]); 196. } 197. 198. System.out.println("==============================================="); 199. 200. //取得类实现的接口,因为接口类也属于Class,所以得到接口中的方法也是一样的方法得到哈 201. Class<?> interfaces[] = class1.getInterfaces(); 202. for (int i = 0; i < interfaces.length; i++) { 203. System.out.println("实现的接口类名: " + interfaces[i].getName() ); 204. } 205. 206. } 207. 208. /** 209. * Demo7: 通过Java反射机制调用类方法 210. * @throws ClassNotFoundException 211. * @throws NoSuchMethodException 212. * @throws SecurityException 213. * @throws InvocationTargetException 214. * @throws IllegalAccessException 215. * @throws IllegalArgumentException 216. * @throws InstantiationException 217. */ 218. public static void Demo7() throws ClassNotFoundException, SecurityException, NoSuchMethodException, IllegalArgumentException, IllegalAccessException, InvocationTargetException, InstantiationException 219. { 220. Class<?> class1 = null; 221. class1 = Class.forName("cn.lee.demo.SuperMan"); 222. 223. System.out.println("Demo7: \n调用无参方法fly():"); 224. Method method = class1.getMethod("fly"); 225. method.invoke(class1.newInstance()); 226. 227. System.out.println("调用有参方法walk(int m):"); 228. method = class1.getMethod("walk",int.class); 229. method.invoke(class1.newInstance(),100); 230. } 231. 232. /** 233. * Demo8: 通过Java反射机制得到类加载器信息 234. * 235. * 在java中有三种类类加载器。[这段资料网上截取] 236. 237. 1)Bootstrap ClassLoader 此加载器采用c++编写,一般开发中很少见。 238. 239. 2)Extension ClassLoader 用来进行扩展类的加载,一般对应的是jre\lib\ext目录中的类 240. 241. 3)AppClassLoader 加载classpath指定的类,是最常用的加载器。同时也是java中默认的加载器。 242. * 243. * @throws ClassNotFoundException 244. */ 245. public static void Demo8() throws ClassNotFoundException 246. { 247. Class<?> class1 = null; 248. class1 = Class.forName("cn.lee.demo.SuperMan"); 249. String nameString = class1.getClassLoader().getClass().getName(); 250. 251. System.out.println("Demo8: 类加载器类名: " + nameString); 252. } 253. 254. 255. 256.} 262.class Person{ 263. private int age; 264. private String name; 265. public Person(){ 266. 267. } 268. public Person(int age, String name){ 269. this.age = age; 270. this.name = name; 271. } 272. 273. public int getAge() { 274. return age; 275. } 276. public void setAge(int age) { 277. this.age = age; 278. } 279. public String getName() { 280. return name; 281. } 282. public void setName(String name) { 283. this.name = name; 284. } 285.} 286. 287.class SuperMan extends Person implements ActionInterface 288.{ 289. private boolean BlueBriefs; 290. 291. public void fly() 292. { 293. System.out.println("超人会飞耶~~"); 294. } 295. 296. public boolean isBlueBriefs() { 297. return BlueBriefs; 298. } 299. public void setBlueBriefs(boolean blueBriefs) { 300. BlueBriefs = blueBriefs; 301. } 302. 303. @Override 304. public void walk(int m) { 305. // TODO Auto-generated method stub 306. System.out.println("超人会走耶~~走了" + m + "米就走不动了!"); 307. } 308.} 309.interface ActionInterface{ 310. public void walk(int m); 311.}