Java 反射机制
来源:互联网 发布:淘宝改后台软件 编辑:程序博客网 时间:2024/06/15 15:23
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.}
- 【反射】JAVA反射机制
- 【Java】JAVA反射机制
- Java 反射机制[Field反射]
- Java 反射机制[Method反射]
- Java反射机制笔记-反射机制
- java的反射机制
- Java的反射机制
- java反射机制详解!
- Java反射机制
- Java的反射机制
- java 反射机制--侯捷
- java反射机制
- java反射机制
- [候捷]Java反射机制
- java 反射机制
- java 反射机制初探
- 关于Java反射机制
- java反射机制
- 【BZOJ 1800】[Ahoi2009]fly 飞行棋
- UVa 11181 Probability|Given
- 关于SSH,插入数据时,,遇到的关于date的问题
- javaWEB总结(5):GET与POST请求
- Java I/O
- Java 反射机制
- php源码之路第五章第三节 (访问控制的实现)
- 获取设备唯一标识
- 利用 DevStack 来部署测试 OVN (Open Virtual Network)
- 从出门开始
- 必须添加对程序集“EntityFramework, Version=5.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089”的引用。
- 38. Count and Say
- Yii2.0 session
- Android ServiceUtils-服务相关工具类