JAVA反射及其实例
来源:互联网 发布:excel表格重复数据筛选 编辑:程序博客网 时间:2024/05/16 18:38
这一篇并不想过多的介绍Java中关于反射的概念,我想即便是对于Java的初学者而言也并不感到陌生,该篇将一如既往的为您提供大量的可执行示例代码和丰富的注释信息,尽可能覆盖Java反射的各个技术环节,从更多的视角为您剖析反射的机制和应用场景,以及它在效率方面的不尽如人意之处。
1. 类属性反射:
每一个Java对象都会包含一个描述其属性(metadata)信息的类对象,该对象将作为Java反射中最重要的一个入口点,几乎所有和反射相关的应用都是从这里开始的。
1) 反射类的名字:
1 public static void main(String[] args) { 2 String str = "Hello"; 3 //1. 获取Java对象的类对象(Class),也可以通过class域字段直接获取,如: 4 //c = str.class; 5 Class<? extends String> c = str.getClass(); 6 //2. 获取Java对象的字符串表示的名称 7 System.out.println(c.getName()); 8 } 9 /* 输出结果如下:10 java.lang.String11 */
2) 通过表示类名称的字符串获取该类的对象实例:
1 public static void main(String[] args) { 2 try { 3 //1. 通过表示类名的字符串,获取该类的类对象(描述String的类metadata信息) 4 Class<?> cls = Class.forName("java.lang.String"); 5 //2. 再通过Class<String>对象的newInstance方法来构造 6 //String的实例,这样要求被实例化的类带有缺省构造函数。 7 //因为newInstance方法只有这一种签名方式。 8 String s = (String) cls.newInstance(); 9 } catch (ClassNotFoundException e) {10 e.printStackTrace();11 } catch (InstantiationException e) {12 e.printStackTrace();13 } catch (IllegalAccessException e) {14 e.printStackTrace();15 }16 }
3) 反射类的修饰符:
1 public static void main(String[] args) { 2 String str = "Hello"; 3 Class<? extends String> c = str.getClass(); 4 //获取的类在声明时定义的修饰符,既该类是否为public、final和abstract 5 int m = c.getModifiers(); 6 if (Modifier.isPublic(m)) 7 System.out.println("public"); 8 if (Modifier.isAbstract(m)) 9 System.out.println("abstract");10 if (Modifier.isFinal(m))11 System.out.println("final");12 }13 /* 输出结果如下:14 public15 final16 */
4) 获取类的域字段、构造函数和域方法的访问修饰符信息:
1 public class MyTest { 2 public static void main(String[] args) { 3 MyTest pp = new MyTest(); 4 pp.doClass("java.lang.String"); 5 } 6 protected void doClass(String className) { 7 try { 8 Class<?> c = Class.forName(className); 9 System.out.println(Modifier.toString(c.getModifiers()) + ' ' + c + " {");10 //通过类的metadata属性信息,获取类的域字段,但是不包括超类中的字段11 //这其中getFields()方法将仅仅返回当前类的public域字段12 Field fields[] = c.getDeclaredFields();13 for (Field f : fields) {14 if (Modifier.isPrivate(f.getModifiers())) {15 System.out.println("Field '" + f.getName() + "' is private.");16 } else if (Modifier.isProtected(f.getModifiers())) {17 System.out.println("Field '" + f.getName() + "' is protected.");18 } else if (Modifier.isPublic(f.getModifiers())) {19 System.out.println("Field '" + f.getName() + "' is public.");20 } else if (Modifier.isFinal(f.getModifiers())) {21 System.out.println("Field '" + f.getName() + "' is final.");22 } else if (Modifier.isStatic(f.getModifiers())) {23 System.out.println("Field '" + f.getName() + "' is static.");24 }25 }26 //获取类的构造函数,getConstructors仅仅返回该类的public构造函数。27 //如果希望获得全部的构造函数,调用getDeclaredConstructors28 Constructor<?>[] constructors = c.getConstructors();29 for (Constructor<?> ctor : constructors) {30 if (Modifier.isProtected(ctor.getModifiers())) {31 System.out.println("Constructor '" + ctor.getName() + "' is protected.");32 } else if (Modifier.isPrivate(ctor.getModifiers())) {33 System.out.println("Constructor '" + ctor.getName() + "' is private.");34 } else if (Modifier.isPublic(ctor.getModifiers())) {35 System.out.println("Constructor '" + ctor.getName() + "' is public.");36 } 37 }38 //获取类中声明的域方法,但是不包含超类中的方法。39 //这其中getMethods()方法将仅仅返回当前类的public域方法40 Method methods[] = c.getDeclaredMethods();41 for (Method m : methods) {42 if (Modifier.isProtected(m.getModifiers())) {43 System.out.println("Method '" + m.getName() + "' is protected.");44 } else if (Modifier.isPrivate(m.getModifiers())) {45 System.out.println("Method '" + m.getName() + "' is private.");46 } else if (Modifier.isPublic(m.getModifiers())) {47 System.out.println("Method '" + m.getName() + "' is public.");48 } else if (Modifier.isStatic(m.getModifiers())) {49 System.out.println("Method '" + m.getName() + "' is static.");50 } else if (Modifier.isNative(m.getModifiers())) {51 System.out.println("Method '" + m.getName() + "' is native.");52 } else if (Modifier.isAbstract(m.getModifiers())) {53 System.out.println("Method '" + m.getName() + "' is abstract.");54 } else if (Modifier.isFinal(m.getModifiers())) {55 System.out.println("Method '" + m.getName() + "' is final.");56 } 57 }58 System.out.println("}");59 } catch (ClassNotFoundException e) {60 System.err.println("Error: Class " + className + " not found!");61 } catch (Exception e) {62 System.err.println(e);63 }64 }65 }
5) 获取超类的名称:
1 public static void main(String[] args) { 2 Class<?> subclass = LinkedList.class; 3 //获取超类的Class对象。 4 Class<?> superclass = subclass.getSuperclass(); 5 while (superclass != null) { 6 String className = superclass.getName(); 7 System.out.println(className); 8 subclass = superclass; 9 superclass = subclass.getSuperclass();10 }11 }12 /* 输出结果如下:13 java.util.AbstractSequentialList14 java.util.AbstractList15 java.util.AbstractCollection16 java.lang.Object17 */
6) 获取实现的接口:
在Java中并没有像C++那样支持多重继承,而是提供了一种更为安全和合理的方式,即单一继承和多实现,这里的单一继承是指继承(extends)一个超类,多实现是指可以实现(implements)多个接口。下面的例子将让我们获取某个类所实现的接口,如下:
1 public static void main(String[] args) { 2 Class<?>[] interfaces = LinkedList.class.getInterfaces(); 3 if ((interfaces != null) && (interfaces.length > 0)) { 4 if (LinkedList.class.isInterface()) 5 System.out.print(" extends "); 6 else 7 System.out.print(" implements "); 8 for (int i = 0; i < interfaces.length; i++) { 9 if (i > 0)10 System.out.print(", ");11 System.out.print(interfaces[i].getName());12 }13 }14 }15 /* 输出结果如下:16 implements java.util.List, java.util.Deque, java.lang.Cloneable, java.io.Serializable 17 */
7) 获取包名:
1 public static void main(String[] args) {2 System.out.println(String.class.getPackage().getName());3 }4 /* 输出结果如下:5 java.lang6 */
2. 基于数组的反射:
1) 通过反射创建数组实例:
1 public static void main(String[] args) { 2 int[] dim1 = { 5 }; 3 //通过Array的newInstance方法构造新的数组实例,这里的dim1定义了 4 //oneDimA的维度,以及在该维度内的长度 5 int[] oneDimA = (int[]) Array.newInstance(int.class, dim1); 6 //第二个参数定义了一维数组的长度 7 int[] oneDimB = (int[]) Array.newInstance(int.class, 5); 8 System.out.println("The length of oneDimA is " + oneDimA.length); 9 System.out.println("The length of oneDimB is " + oneDimB.length);10 if (Arrays.equals(oneDimA, oneDimB))11 System.out.println("OneDimA is equal to oneDimB");12 13 int[] dimStr = { 5, 10 };14 //这里通过dimStr来定义一个5*10的二维String数组。15 String[][] twoDimStr = (String[][]) Array.newInstance(String.class,dimStr);16 System.out.println("The length of twoDimStr is " + twoDimStr.length);17 for (int i = 0; i < twoDimStr.length; ++i) {18 System.out.print(twoDimStr[i].length + "\t");19 }20 }21 /* 输出结果如下:22 The length of oneDimA is 523 The length of oneDimB is 524 OneDimA is equal to oneDimB25 The length of twoDimStr is 526 10 10 10 10 10 27 */
2) 获取原始类型和原始类型数组的类型名称:
1 public static void main(String[] args) { 2 System.out.println(int.class.getName()); 3 System.out.println(int[].class.getName()); 4 System.out.println(byte.class.getName()); 5 System.out.println(byte[].class.getName()); 6 } 7 /* 输出结果如下: 8 int 9 [I10 byte11 [B12 */
可以看到数组的名称前面带有一个[,这是数组名称的表示方式,二维数组则表示为[[,后面的I表示int,B表示byte。这是JVM提供的一套类型名称编码规范,我会在后面关于本地代码(JNI)的Blog中给出更为明确的列表和使用方式,因为他们在JNI中应用还是比较广泛的。
3) 判断当前对象是否为数组:
1 public static void main(String[] args) { 2 Object o = new int[10]; 3 boolean b = o.getClass().isArray(); 4 if (b) { 5 System.out.println("object is an array"); 6 } 7 } 8 /* 输出结果如下: 9 object is an array 10 */
4) 获取数组的维度:
1 public class MyTest { 2 public static void main(String[] args) { 3 Object o = new int[1][2][3]; 4 System.out.println("The length is " + Array.getLength(o)); 5 System.out.println("The Dimension is " + getDim(o)); 6 } 7 public static int getDim(Object array) { 8 int dim = 0; 9 Class<?> cls = array.getClass();10 while (cls.isArray()) {11 ++dim;12 //getComponentType获取数组元素的Class对象,13 //如果不是数组返回null。14 cls = cls.getComponentType();15 }16 return dim;17 }18 }19 /* 输出结果如下:20 The length is 121 The Dimension is 3 22 */
5) 通过反射填充和显示数组元素:
1 public class MyTest { 2 public static void main(String args[]) { 3 Object array = Array.newInstance(int.class, 3); 4 fillArray(array); 5 displayArray(array); 6 } 7 private static void fillArray(Object array) { 8 //这里是通过反射的方式获取数组的长度,效率会低于 9 //通过数组对象的length方法获取,因此这里的例子缓存10 //了该长度,而不是直接放到for循环的第二个表达式11 int length = Array.getLength(array);12 for (int i = 0; i < length; i++) {13 //设置array数组的第i个元素的值为i*i。14 Array.setInt(array, i, i*i);15 }16 }17 private static void displayArray(Object array) {18 int length = Array.getLength(array);19 for (int i = 0; i < length; i++) {20 //获取array数组的第i个元素,并返回int值。21 int value = Array.getInt(array, i);22 System.out.println("Position: " + i + ", value: " + value);23 }24 }25 }26 /* 输出结果如下:27 Position: 0, value: 028 Position: 1, value: 129 Position: 2, value: 430 */
6) 基于数组对象再通过反射的机制创建一个相同的数组对象:
1 public class MyTest { 2 public static void main(String args[]) { 3 int[] ints = new int[2]; 4 Object ret = buildNewArrayWithReflection(ints); 5 if (ret != null) { 6 Arrays.equals(ints, (int[])ret); 7 System.out.println("The both array are equal."); 8 } 9 }10 private static Object buildNewArrayWithReflection(Object source) {11 if (!source.getClass().isArray()) {12 System.out.println("The argument is NOT an array.");13 return null;14 }15 Class<?> arrayClass = source.getClass();16 String arrayName = arrayClass.getName();17 Class<?> componentClass = arrayClass.getComponentType();18 String componentName = componentClass.getName();19 System.out.println("Array: " + arrayName + ", Component: " + componentName);20 int length = Array.getLength(source);21 Object ret = Array.newInstance(componentClass, length);22 System.arraycopy(source, 0, ret, 0, length);23 return ret;24 }25 }26 /* 输出结果如下:27 Array: [I, Component: int28 The both array are equal.29 */
3. 基于对象域字段的反射:
1) 列出对象的public域字段和所有声明的域字段(不包含超类的):
1 public class MyTest { 2 public static void main(String args[]) { 3 Class<Point> cls = java.awt.Point.class; 4 Field[] fieldPublic = cls.getFields(); 5 System.out.println("Here are public fields."); 6 for (Field f : fieldPublic) { 7 System.out.println(f.getType()); 8 } 9 Field[] fieldDeclared = cls.getDeclaredFields();10 System.out.println("Here are all declared fields including private "11 + "and static and protect.");12 for (Field f : fieldDeclared) {13 System.out.println(f.getType());14 }15 }16 }17 /* 输出结果如下:18 Here are public fields.19 int20 int21 Here are all declared fields including private and static and protect.22 int23 int24 long25 */
2) 基于域字段的字符串名称获取该域字段的值:
1 public class MyTest { 2 public static void main(String args[]) throws Exception { 3 Object o = new TestClass(); 4 //根据域字段的字符串名字反射出与该字段对应Field类对象。 5 Field field = o.getClass().getField("firstValue"); 6 //获取该域字段类型的Class对象。 7 Class<?> type = field.getType(); 8 //根据域字段的类型,调用Field.getXxx()方法获取该对象域字段的值。 9 if (type.toString().equals("double"))10 System.out.println(field.getDouble(o));11 else if (type.toString().equals("int"))12 System.out.println(field.getInt(o));13 }14 }15 16 class TestClass {17 public double firstValue = 3.14;18 }19 /* 输出结果如下:20 3.14 21 */
3) 获取和设置指定域字段的值:
1 public class MyTest { 2 public static void main(String args[]) throws Exception { 3 Bean demo = new Bean(); 4 Class<? extends Bean> cl = demo.getClass(); 5 6 Field field = cl.getField("id"); 7 field.set(demo, new Long(10)); 8 Object value = field.get(demo); 9 System.out.println("Value = " + value);10 11 field = cl.getField("now");12 field.set(null, new Date());13 value = field.get(null);14 System.out.println("Value = " + value);15 }16 }17 class Bean {18 public static Date now;19 public Long id;20 public String name;21 } 22 /* 输出结果如下:23 Value = 1024 Value = Sun Sep 04 11:38:15 CST 201125 */
4. 泛型信息的反射:
1) 获取类的泛型接口信息
1 public static void main(String args[]) throws Exception { 2 Class<?> c = Class.forName("java.util.ArrayList"); 3 System.out.format("Class:%n %s%n", c.getCanonicalName()); 4 System.out.format("Modifiers:%n %s%n", 5 Modifier.toString(c.getModifiers())); 6 7 System.out.format("Type Parameters:%n"); 8 //获取该泛型类的类型参数数组 9 TypeVariable[] tv = c.getTypeParameters();10 if (tv.length != 0) {11 System.out.format(" ");12 for (TypeVariable t : tv)13 System.out.format("%s ", t.getName());14 System.out.println();15 } else {16 System.out.format(" -- No Type Parameters --%n%n");17 }18 19 System.out.format("Implemented Interfaces:%n");20 //获取该类实现的接口,如果实现的接口为泛型接口,则打印出他的类型参数。21 //getInterfaces()不会打印出类型参数。22 Type[] intfs = c.getGenericInterfaces();23 if (intfs.length != 0) {24 for (Type intf : intfs)25 System.out.format(" %s%n", intf.toString());26 System.out.format("%n");27 } else {28 System.out.format(" -- No Implemented Interfaces --%n%n");29 }30 }31 /* 输出结果如下:32 Class:33 java.util.ArrayList34 Modifiers:35 public36 Type Parameters:37 E 38 Implemented Interfaces:39 java.util.List<E>40 interface java.util.RandomAccess41 interface java.lang.Cloneable42 interface java.io.Serializable 43 */
2) 获取类的泛型接口、接口、泛型超类和超类信息的比较:
1 public static void main(String args[]) throws Exception { 2 //1. 超类 3 Class<?> ts = TreeMap.class.getSuperclass(); 4 System.out.println(ts + "\n"); 5 //2. 如果超类为泛型类,输出该泛型超类的类型信息。 6 Type t = TreeMap.class.getGenericSuperclass(); 7 System.out.println(t + "\n"); 8 //3. 接口 9 Class<?>[] is = TreeMap.class.getInterfaces();10 for (int i = 0; i < is.length; i++) {11 System.out.println(is[i]);12 }13 System.out.println();14 //2. 如果接口为泛型接口,输出该泛型接口的类型信息。15 Type[] ts2 = TreeMap.class.getGenericInterfaces();16 for (int i = 0; i < ts2.length; i++) {17 System.out.println(ts2[i]);18 }19 }20 /* 输出结果如下:21 class java.util.AbstractMap22 23 java.util.AbstractMap<K, V> 24 25 interface java.util.NavigableMap26 interface java.lang.Cloneable27 interface java.io.Serializable28 29 java.util.NavigableMap<K, V>30 interface java.lang.Cloneable31 interface java.io.Serializable 32 */
3) 输出域方法的签名信息,包括返回值和参数列表的泛型类型信息:
1 import static java.lang.System.out; 2 public class MyTest { 3 private static final String fmt = "%24s: %s%n"; 4 public static void main(String args[]) throws Exception { 5 Class<?> c = Class.forName("java.util.ArrayList"); 6 Method[] allMethods = c.getDeclaredMethods(); 7 for (Method m : allMethods) { 8 //1. 获取域方法的完整描述,如果是泛型方法,则会给出类型信息 9 out.format("%s%n", m.toGenericString());10 //2. 获取返回值类型11 out.format(fmt, "ReturnType", m.getReturnType());12 //3. 获取返回值类型,如为泛型类型,则打印出类型信息13 out.format(fmt, "GenericReturnType", m.getGenericReturnType());14 //4. 获取参数列表15 Class<?>[] pType = m.getParameterTypes();16 //5. 获取参数列表,如为泛型参数,则打印出类型信息17 Type[] gpType = m.getGenericParameterTypes();18 for (int i = 0; i < pType.length; i++) {19 out.format(fmt, "ParameterType", pType[i]);20 out.format(fmt, "GenericParameterType", gpType[i]);21 }22 }23 }24 }25 /* 输出结果如下(由于输出较长,这里只是给出有代表性的输出):26 ... ...27 public void java.util.ArrayList.add(int,E)28 ReturnType: void29 GenericReturnType: void30 ParameterType: int31 GenericParameterType: int32 ParameterType: class java.lang.Object33 GenericParameterType: E 34 ... ...35 public <T> T[] java.util.ArrayList.toArray(T[])36 ReturnType: class [Ljava.lang.Object;37 GenericReturnType: T[]38 ParameterType: class [Ljava.lang.Object;39 GenericParameterType: T[]40 ... ...41 */
4) 输出对象域字段的类型信息:
1 public class MyTest<T> { 2 public String name = "Alice"; 3 public List<Integer> list; 4 public T val; 5 6 public static void main(String args[]) throws Exception { 7 Class<?> c = Class.forName("MyTest"); 8 for (Field f : c.getFields()) { 9 //getType和getGenericType之间的差异和上面用到的10 //getReturnType和getGenericReturnType之间的差别相同11 System.out.format("Type: %s%n", f.getType());12 System.out.format("GenericType: %s%n", f.getGenericType());13 }14 }15 }16 /* 输出结果如下:17 Type: class java.lang.String18 GenericType: class java.lang.String19 Type: interface java.util.List20 GenericType: java.util.List<java.lang.Integer>21 Type: class java.lang.Object22 GenericType: T 23 */
5. 枚举的反射:
1) 获取枚举的常量列表:
1 import static java.lang.System.out; 2 public class MyTest { 3 public static void main(String args[]) throws Exception { 4 //判断该类是否为枚举 5 if (!Eon.class.isEnum()) 6 return; 7 Class<?> c = Eon.class; 8 out.format("Enum name: %s%nEnum constants: %s%n", c.getName(), 9 Arrays.asList(c.getEnumConstants()));10 Eon[] vs = Eon.values();11 for (Eon e : vs) {12 out.println("The name is " + e.name() + "\tThe ordinal is " + e.ordinal());13 }14 }15 }16 17 enum Eon {18 HADEAN, ARCHAEAN, PROTEROZOIC, PHANEROZOIC19 }20 /* 输出结果如下:21 Enum name: Eon22 Enum constants: [HADEAN, ARCHAEAN, PROTEROZOIC, PHANEROZOIC]23 The name is HADEAN The ordinal is 024 The name is ARCHAEAN The ordinal is 125 The name is PROTEROZOIC The ordinal is 226 The name is PHANEROZOIC The ordinal is 327 */
6. 域方法的反射:
1) 通过类构造器的反射对象构造新实例:
1 public static void main(String args[]) throws Exception { 2 //根据构造函数的参数列表获取Point类的带有该参数列表的构造函数的反射类 3 //该构造函数的原型为Point(int x,int y); 4 Constructor<Point> con = Point.class.getConstructor(new Class[] { 5 int.class, int.class }); 6 //由于参数必须是Object的数组表示,因此对于Point构造的两个 7 //int参数,只能使用他们的包括类Integer. 8 Point obj = (Point) con.newInstance(new Object[] { 9 new Integer(123), new Integer(123) });10 System.out.println(obj);11 }12 /* 输出结果如下:13 java.awt.Point[x=123,y=123] 14 */
2) 通过域方法的名称和参数列表签名获取并执行该方法(静态方法):
1 public static void main(String args[]) throws Exception { 2 //通过方法名称和参数列表签名获取类的静态域方法。 3 Method m = Math.class.getMethod("sqrt", new Class[] { double.class }); 4 //由于是静态方法,第一个参数传null,如是是非静态函数,可以 5 //该参数看成this引用,传递对象即可,后面的参数列表表示该 6 //反射方法的参数列表。这里Math.sqrt只有一个double类型的 7 //参数。invoke的返回值只能是Object类型,因此也只能先将其 8 //转换为原始类型的包装类型,在从包装类型获取原始类型。 9 Double o = (Double)m.invoke(null, 10);10 System.out.println(o.doubleValue());11 }12 /* 输出结果如下:13 3.162277660168379514 */
3) 通过域方法的名称和参数列表签名获取并执行该方法(非静态方法):
1 public class MyTest { 2 public static void main(String args[]) throws Exception { 3 String firstWord = "Hello "; 4 String secondWord = "everybody."; 5 String bothWords = append(firstWord, secondWord); 6 System.out.println(bothWords); 7 } 8 9 public static String append(String firstWord, String secondWord) {10 String result = null;11 Class<String> c = String.class;12 //初始化域方法的参数类型列表13 Class<?>[] parameterTypes = new Class[] { String.class };14 Method concatMethod;15 //初始化域方法的参数16 Object[] arguments = new Object[] { secondWord };17 try {18 //根据域方法的名称和参数列表获取域方法的反射对象19 concatMethod = c.getMethod("concat", parameterTypes);20 //和静态方法的反射调用不同,这里的第一个参数必须填入,其作用21 //相当于firstWord.concat(secondword);22 result = (String) concatMethod.invoke(firstWord, arguments);23 } catch (NoSuchMethodException e) {24 System.out.println(e);25 } catch (IllegalAccessException e) {26 System.out.println(e);27 } catch (InvocationTargetException e) {28 System.out.println(e);29 }30 return result;31 }32 } 33 /* 输出结果如下:34 Hello everybody.35 */
4) 通过反射调用对象的私有域方法:
1 public class MyTest { 2 public static void main(String args[]) throws Exception { 3 TestClass tc = new TestClass(); 4 Class<?> c = tc.getClass(); 5 Method m = c.getDeclaredMethod("m"); 6 //必须调用该方法通过反射的方法设置这个private的可访问性 7 //为true,否则调用时将会抛出IllegalAccessException异常 8 m.setAccessible(true); 9 Object o = m.invoke(tc);10 }11 }12 class TestClass {13 private void m() {14 System.out.println("This is private method TestClass.m().");15 }16 }17 /* 输出结果如下:18 This is private method TestClass.m().19 */
5) 通过栈帧获取当前方法的名称:
1 public static void main(String args[]) throws Exception { 2 System.out.println(new Exception().getStackTrace()[0].getMethodName()); 3 4 //这里的第0帧为getStackTrace() 5 System.out.println(Thread.currentThread().getStackTrace()[1].getFileName()); 6 System.out.println(Thread.currentThread().getStackTrace()[1].getClassName()); 7 System.out.println(Thread.currentThread().getStackTrace()[1].getMethodName()); 8 System.out.println(Thread.currentThread().getStackTrace()[1].getLineNumber()); 9 10 }11 /* 输出结果如下:12 main13 MyTest.java14 MyTest15 main16 1217 */
7. 基于反射的方法调用和普通的方法调用之间的效率差别:
我们在本篇开始的部分已经提到反射确实可以给我们的程序带来极大的灵活性,目前很多流行的框架都是非常依赖于Java提供的反射机制,反射几乎处处可见。然而这并不能成为我们滥用他的理由,还是那句话,没有免费的午餐,反射的灵活性是用极大的效率牺牲换来的,见下例:
1 public class MyTest { 2 public static void main(String args[]) throws Exception { 3 try { 4 final int CALL_AMOUNT = 1000000; 5 final MyTest ri = new MyTest(); 6 int idx = 0; 7 //1. 直接使用正常的方法调用(没有反射) 8 long millis = System.currentTimeMillis(); 9 for (idx = 0; idx < CALL_AMOUNT; ++idx)10 ri.getValue();11 System.out.println("Calling method " + CALL_AMOUNT12 + " times programatically took "13 + (System.currentTimeMillis() - millis) + " millis");14 15 //2. 通过反射调用域方法,而且每次都重新获取该域方法的反射类。16 millis = System.currentTimeMillis();17 for (idx = 0; idx < CALL_AMOUNT; idx++) {18 Method md = ri.getClass().getMethod("getValue", null);19 md.invoke(ri, null);20 }21 System.out.println("Calling method " + CALL_AMOUNT22 + " times reflexively with lookup took "23 + (System.currentTimeMillis() - millis) + " millis");24 25 //3.通过反射调用域方法,但是该方法的反射对象并不是每次都26 //重新获取,而是重复使用,只是在域方法调用的时候通过反射完成。27 Method md = ri.getClass().getMethod("getValue", null);28 millis = System.currentTimeMillis();29 for (idx = 0; idx < CALL_AMOUNT; idx++)30 md.invoke(ri, null);31 System.out.println("Calling method " + CALL_AMOUNT32 + " times reflexively with cache took "33 + (System.currentTimeMillis() - millis) + " millis");34 } catch (final NoSuchMethodException ex) {35 throw new RuntimeException(ex);36 } catch (final InvocationTargetException ex) {37 throw new RuntimeException(ex);38 } catch (final IllegalAccessException ex) {39 throw new RuntimeException(ex);40 }41 }42 public String getValue() {43 return this.value;44 }45 private String value = "some value";46 } 47 /* 输出结果如下:48 Calling method 1000000 times programatically took 0 millis49 Calling method 1000000 times reflexively with lookup took 1422 millis50 Calling method 1000000 times reflexively with cache took 110 millis51 */
- JAVA反射及其实例
- Java反射及其应用
- Java反射实例
- java反射实例
- Java反射经典实例
- Java反射经典实例
- Java经典反射实例
- Java反射经典实例
- Java反射经典实例
- java反射经典实例
- Java反射经典实例
- java反射实例
- java反射实例
- java反射经典实例
- Java反射经典实例
- Java反射经典实例
- Java反射经典实例
- Java反射经典实例
- linux下生成rsa的key对
- 修改应用亮度和系统亮度
- 无奈!浮沉华世
- Spring自动代理创建器
- java网路编程学习之路(2)
- JAVA反射及其实例
- jquery-学习笔记1
- 调整积极心态,让工作更加高效、顺利
- rpy2 图形,summary 显示
- spring mvc 小贴士
- 红黑树
- 不使用库函数将字符串转为double类型(考虑科学计数法表示的字符串)
- 新闻源的推广好处
- Jquery学习笔记(3):iScroll问题总结