看到一篇java反射机制的文章,写的不错,于是摘抄下重点部分,方便以后的复习:
原文地址:http://www.cnblogs.com/forlina/archive/2011/06/21/2085849.html#undefined
1.什么是Java中的类反射:Reflection 是 Java 程序开发语言的特征之一,它允许运行中的 Java 程序对自身进行检查,或者说“自审”,并能直接操作程序的内部属性和方法。Java 的这一能力在实际应用中用得不是很多,但是在其它的程序设计语言中根本就不存在这一特性。例如,Pascal、C 或者 C++ 中就没有办法在程序中获得函数定义相关的信息。
Reflection 是 Java 被视为动态(或准动态)语言的关键,允许程序于执行期 Reflection APIs 取得任何已知名称之 class 的內部信息,包括 package、type parameters、superclass、implemented interfaces、inner classes, outer class, fields、constructors、methods、modifiers,並可于执行期生成instances、变更 fields 內容或唤起 methods。
2.Java的类反射所需要的类并不多,它们分别是:Field、Constructor、Method、Class、Object,下面我将对这些类做一个简单的说明。
Field类:提供有关类或接口的属性的信息,以及对它的动态访问权限。反射的字段可能是一个类(静态)属性或实例属性,简单的理解可以把它看成一个封装反射类的属性的类。
Constructor类:提供关于类的单个构造方法的信息以及对它的访问权限。这个类和Field类不同,Field类封装了反射类的属性,而Constructor类则封装了反射类的构造方法。
Method类:提供关于类或接口上单独某个方法的信息。所反映的方法可能是类方法或实例方法(包括抽象方法)。 这个类不难理解,它是用来封装反射类方法的一个类。
Class类:类的实例表示正在运行的 Java 应用程序中的类和接口。枚举是一种类,注释是一种接口。每个数组属于被映射为 Class 对象的一个类,所有具有相同元素类型和维数的数组都共享该 Class 对象。
Object类:每个类都使用 Object 作为超类。所有对象(包括数组)都实现这个类的方法。
一个简单的例子如下所示:
1 package com.pcitc.reflect; 2 3 import java.awt.event.ActionEvent; 4 import java.awt.event.ActionListener; 5 import java.lang.reflect.Constructor; 6 import java.lang.reflect.Field; 7 import java.lang.reflect.Method; 8 9 public class TestReflect extends Object implements ActionListener { 10 private int a = 3; 11 public Integer b = new Integer(4); 12 13 public TestReflect() { 14 } 15 16 public TestReflect(int id, String name) { 17 } 18 19 public int abc(int id, String name) { 20 return 0; 21 } 22 23 public void actionPerformed(ActionEvent e) { 24 } 25 26 public static void main(String[] args) { 27 TestReflect tr = new TestReflect(); 28 Class trClass = tr.getClass(); 29 // 操作反射类的相关属性 30 getReflectFields(trClass); 31 // 操作反射类的构造方法 32 getReflectConstructors(trClass); 33 // 操作反射类的父类和实现的接口 34 getReflectionSuper_Interface(trClass); 35 // 操作反射类的相关成员方法 36 getReflectionMethod(trClass); 37 } 38 39 /** 40 * 用于操作反射类的属性的方法:该方法用到了反射类的两个方法:getFields()和getDeclaredFields()。getFields() 41 * 用来获取反射类中所有公有属性, getDeclaredFields()用于获取反射类中所有的属性的方法。 42 * 另外还有getField(String)和getDeclaredField(String)方法都是用来过去反射类中指定的属性的方法, 要注意的 43 * 是getField方法只能取到反射类中公有的属性,而getDeclaredField方法都能取到。 这里还用到了Field 44 * 类的setAccessible方法,它是用来设置是否有权限访问反射类中的私有属性的,只有设置为true时才可以访问, 默认为false。另外 45 * Field类还有set(Object AttributeName,Object value)方法,可以改变指定属性的值。 46 * 47 * @author xxx 48 * @created 2015年5月25日 下午3:38:05 49 * @param c 50 */ 51 public static void getReflectFields(Class trClass) { 52 System.out.println("++++++++++++++操作反射类的属性+++++++++++++"); 53 System.out.println("获取反射类中所有公有的属性:"); 54 Field[] fieldsPub = trClass.getFields(); 55 for (Field field : fieldsPub) { 56 System.out.println(field.getType() + ":" + field.getName()); 57 } 58 System.out.println("获取反射类中所有的属性:"); 59 Field[] fieldsAll = trClass.getDeclaredFields(); 60 for (Field field : fieldsAll) { 61 System.out.println(field.getType() + ":" + field.getName()); 62 } 63 64 System.out.println("获取反射类中的私有属性a:"); 65 try { 66 Field a = trClass.getDeclaredField("a"); 67 a.setAccessible(true); 68 System.out.println(a.getType() + ":" + a.getName()); 69 } catch (NoSuchFieldException e) { 70 // TODO Auto-generated catch block 71 e.printStackTrace(); 72 } catch (SecurityException e) { 73 // TODO Auto-generated catch block 74 e.printStackTrace(); 75 } catch (IllegalArgumentException e) { 76 // TODO Auto-generated catch block 77 e.printStackTrace(); 78 } 79 } 80 81 /** 82 * 83 * 用于操作反射类的构造方法的方法:用getConstructors()方法获取了反射类的构造方法的集合, 84 * 并用Constructor类的getParameterTypes()来 获取该构造方法的参数。 85 * 86 * @author xxx 87 * @created 2015年5月25日 下午3:45:10 88 * @param trClass 89 */ 90 public static void getReflectConstructors(Class trClass) { 91 System.out.println("++++++++++++++操作反射类的构造方法+++++++++++++"); 92 System.out.println("获取指定类的类名:"); 93 System.out.println(trClass.getName()); 94 Constructor[] cArr = trClass.getConstructors(); 95 System.out.println("获取反射类指定构造方法的参数集合:"); 96 for (Constructor c : cArr) { 97 Class[] parameters = c.getParameterTypes(); 98 for (Class parameter : parameters) { 99 System.out.println(parameter.getName()); 100 } 101 } 102 } 103 104 /** 105 * 用于操作反射类 父类和实现的接口的方法:用Class类的getInterfaces()方法获取反射类的所有接口,由于接口可以有多个,所以它返回一个 106 * Class数组。 用getSuperclass()方法来获取反射类的父类(超类),由于一个类只能继承自一个类,所以它返回一个Class对象。 107 * 108 * @author xxx 109 * @created 2015年5月25日 下午3:48:38 110 * @param trClass 111 */ 112 public static void getReflectionSuper_Interface(Class trClass) { 113 System.out.println("++++++++++++++++++操作反射类的父类(超类)和接口++++++++++++"); 114 Class[] interfaceArr = trClass.getInterfaces(); 115 System.out.println("获取反射类实现的接口:"); 116 for (Class interfaces : interfaceArr) { 117 System.out.println(interfaces.getName()); 118 } 119 Class superClass = trClass.getSuperclass(); 120 System.out.println("获取反射类的父类:"); 121 System.out.println(superClass.getName()); 122 } 123 124 /** 125 * 用于操作反射类成员方法的方法:使用getMethods()获得了反射类的所有方法,包括继承自它父类的方法。然后使用getReturnType() 126 * 获取方法的返回类型、 使用method.getName()获取方法名,使用getParameterTypes()获取方法参数。 127 * 128 * @author xxx 129 * @created 2015年5月25日 下午3:51:26 130 * @param trClass 131 */ 132 public static void getReflectionMethod(Class trClass) { 133 System.out.println("++++++++++++++++++操作反射类的成员方法++++++++++++"); 134 Method[] methods = trClass.getMethods(); 135 for (Method method : methods) { 136 System.out.println("获取反射类的方法名和返回值类型:"); 137 System.out.println(method.getName() + ":" 138 + method.getReturnType().getName()); 139 Class[] parameters = method.getParameterTypes(); 140 System.out.println("方法的参数是:"); 141 for (Class parameter : parameters) { 142 System.out.println(parameter.getName()); 143 } 144 } 145 } 146 }
下文是原作者写的java反射机制实际的一个应用案例,摘抄下来以备忘记:
1 package com.pcitc.reflect; 2 3 import java.lang.reflect.Constructor; 4 import java.lang.reflect.Method; 5 6 public class LoadMethod { 7 // Load方法接收的四个参数分别是,Java的类名,方法名,参数的类型和参数的值。 8 public Object Load(String cName, String MethodName, String[] type, 9 String[] param) { 10 Object retobj = null; 11 try { 12 // 加载指定的Java类 13 Class cls = Class.forName(cName); 14 15 // 获取指定对象的实例 16 Constructor ct = cls.getConstructor(null);// 获取该类的无参构造函数 17 Object obj = ct.newInstance(null);// 调用无参构造函数获取一个对象实例 18 19 // 构建方法参数的数据类型 20 Class parameterTypes[] = this.getMethodClass(type); 21 22 // 通过方法名和方法参数在指定类中获取指定的方法 23 Method method = cls.getMethod(MethodName, parameterTypes); 24 25 // 构建方法的参数值 26 Object arglist[] = this.getMethodObject(type, param); 27 28 // 调用指定的方法并获取返回值为Object类型 29 // obj必须是实例化的 对象 30 retobj = method.invoke(obj, arglist); 31 32 } catch (Throwable e) { 33 System.err.println(e); 34 } 35 return retobj; 36 } 37 38 // 获取参数类型Class[]的方法 39 public Class[] getMethodClass(String[] type) { 40 Class[] cs = new Class[type.length]; 41 for (int i = 0; i < cs.length; i++) { 42 if (!type[i].trim().equals("") || type[i] != null) { 43 if (type[i].equals("int") || type[i].equals("Integer")) { 44 cs[i] = Integer.TYPE; 45 } else if (type[i].equals("float") || type[i].equals("Float")) { 46 cs[i] = Float.TYPE; 47 } else if (type[i].equals("double") || type[i].equals("Double")) { 48 cs[i] = Double.TYPE; 49 } else if (type[i].equals("boolean") 50 || type[i].equals("Boolean")) { 51 cs[i] = Boolean.TYPE; 52 } else { 53 cs[i] = String.class; 54 } 55 } 56 } 57 return cs; 58 } 59 60 // 获取参数Object[]的方法 61 public Object[] getMethodObject(String[] type, String[] param) { 62 Object[] obj = new Object[param.length]; 63 for (int i = 0; i < obj.length; i++) { 64 if (!param[i].trim().equals("") || param[i] != null) { 65 if (type[i].equals("int") || type[i].equals("Integer")) { 66 obj[i] = new Integer(param[i]); 67 } else if (type[i].equals("float") || type[i].equals("Float")) { 68 obj[i] = new Float(param[i]); 69 } else if (type[i].equals("double") || type[i].equals("Double")) { 70 obj[i] = new Double(param[i]); 71 } else if (type[i].equals("boolean") 72 || type[i].equals("Boolean")) { 73 obj[i] = new Boolean(param[i]); 74 } else { 75 obj[i] = param[i]; 76 } 77 } 78 } 79 return obj; 80 } 81 82 public int sum(int i, int j) { 83 return i + j; 84 } 85 86 public static void main(String[] args) { 87 LoadMethod lm = new LoadMethod(); 88 String[] type = { "int", "int" };// 构建参数类型字符串数组 89 String[] params = { "10", "10" };// 构建参数值得字符串数组 90 // 调用Load方法 91 Object obj = lm.Load("com.pcitc.reflect.LoadMethod", "sum", type, 92 params); 93 System.out.println(obj); 94 } 95 }
Java 语言反射提供一种动态链接程序组件的多功能方法。它允许程序创建和控制任何类的对象,无需提前硬编码目标类。这些特性使得反射特别适用于创建以非常普通的 方式与对象协作的库。Java reflection 非常有用,它使类和数据结构能按名称动态检索相关信息,并允许在运行着的程序中操作这些信息。Java 的这一特性非常强大,并且是其它一些常用语言,如 C、C++、Fortran 或者 Pascal 等都不具备的。
但反射有两个缺点。第一个是性能问题。用于字段和方法接入时反射要远 慢于直接代码。性能问题的程度取决于程序中是如何使用反射的。如果它作为程序运行中相对很少涉及的部分,缓慢的性能将不会是一个问题。即使测试中最坏情况 下的计时图显示的反射操作只耗用几微秒。仅反射在性能关键的应用的核心逻辑中使用时性能问题才变得至关重要。