JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法;这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。
通俗地说,反射机制就是可以把一个类,类的成员(函数,属性),当成一个对象来操作,希望读者能理解,也就是说,类,类的成员,我们在运行的时候还可以动态地去操作他们.
Java反射机制主要提供了以下功能: 在运行时判断任意一个对象所属的类;在运行时构造任意一个类的对象;在运行时判断任意一个类所具有的成员变量和方法;在运行时调用任意一个对象的方法;生成动态代理。
从Class类说起
如果你使用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.}