[关闭]
@gnudennis 2015-04-26T15:05:41.000000Z 字数 7664 阅读 2718

Core Java笔记 3.反射

CoreJava


本章重点:

  • Class 类
  • 利用反射分析类
  • 在运行时使用反射分析对象
  • 使用反射编写泛型数组代码
  • 方法指针

能够分析类能力的程序称为反射(reflective). Java 提供了丰富且精心设计的工具集(reflection library).

Class 类

在程序运行期间,Java 运行时系统始终为所有的对象维护着一个运行时的类型标识,这个信息保存着每个对象所属的类足迹.

获取 Class 实例.

  1. // 1. 通过实例获得.
  2. Employee e;
  3. Class cl = e.getClass();
  4. // 2. 通过类名获得.
  5. String className = "java.util.Date";
  6. Class cl = Class.forName(className); // need try...catch
  7. // 3. 通过类获得.
  8. Class cl = Date.class
  9. Class cl = int.class

虚拟机为每个类型管理一个Class对象.

  1. if (e.getClass = Employee.class) ...

通过 Class 创建实例.

  1. e.getClass().newInstance(); // 需要有无参构造器
  2. Date.getClass().newInstance();
  3. Class.forName("xxx").newInstance();

利用反射分析类

java.lang.reflect包中的三个核心类: Field、Method、Constructor.

使用反射分析类

  1. package corejava.reflection;
  2. import java.lang.reflect.Constructor;
  3. import java.lang.reflect.Field;
  4. import java.lang.reflect.Method;
  5. import java.lang.reflect.Modifier;
  6. import java.util.Scanner;
  7. /**
  8. * Created by guolong.fan on 15/4/24.
  9. */
  10. public class ReflectionTest {
  11. public static void main(String[] args) {
  12. String name;
  13. if (args.length > 0) name = args[0];
  14. else {
  15. Scanner in = new Scanner(System.in);
  16. System.out.println("Enter class name(e.g. java.util.Date):");
  17. name = in.next();
  18. }
  19. try {
  20. // print class name and superclass name(if != Object)
  21. Class cl = Class.forName(name);
  22. Class supercl = cl.getSuperclass();
  23. String modifiers = Modifier.toString(cl.getModifiers());
  24. if (modifiers.length() > 0) System.out.print(modifiers + " ");
  25. System.out.print("class " + name);
  26. if (supercl != null && supercl != Object.class) {
  27. System.out.print(" extends " + supercl.getName());
  28. }
  29. System.out.println(" {");
  30. printConstructors(cl);
  31. System.out.println();
  32. printMethods(cl);
  33. System.out.println();
  34. printFields(cl);
  35. System.out.println("}");
  36. } catch (ClassNotFoundException e) {
  37. e.printStackTrace();
  38. }
  39. }
  40. private static void printConstructors(Class cl) {
  41. Constructor[] constructors = cl.getDeclaredConstructors();
  42. for (Constructor c : constructors) {
  43. String name = c.getName();
  44. System.out.print("\t");
  45. String modifiers = Modifier.toString(c.getModifiers());
  46. if (modifiers.length() > 0) System.out.print(modifiers + " ");
  47. System.out.print(name + "(");
  48. Class[] paramTypes = c.getParameterTypes();
  49. for (int j = 0; j < paramTypes.length; ++j) {
  50. if (j > 0) System.out.print(", ");
  51. System.out.print(paramTypes[j].getName());
  52. }
  53. System.out.print(")");
  54. Class[] expTypes = c.getExceptionTypes();
  55. if (expTypes.length > 0) System.out.print(" throws ");
  56. for (int j = 0; j < expTypes.length; ++j) {
  57. if (j > 0) System.out.print(", ");
  58. System.out.print(expTypes[j].getName());
  59. }
  60. System.out.println(";");
  61. }
  62. }
  63. private static void printMethods(Class cl) {
  64. Method[] methods = cl.getDeclaredMethods();
  65. for (Method m : methods) {
  66. String name = cl.getName();
  67. Class refType = m.getReturnType();
  68. System.out.print("\t");
  69. String modifiers = Modifier.toString(m.getModifiers());
  70. if (modifiers.length() > 0) System.out.print(modifiers + " ");
  71. System.out.print(refType.getName() + " ");
  72. System.out.print(name + "(");
  73. Class[] paramTypes = m.getParameterTypes();
  74. for (int j = 0; j < paramTypes.length; ++j) {
  75. if (j > 0) System.out.print(", ");
  76. System.out.print(paramTypes[j].getName());
  77. }
  78. System.out.print(")");
  79. Class[] expTypes = m.getExceptionTypes();
  80. if (expTypes.length > 0) System.out.print(" throws ");
  81. for (int j = 0; j < expTypes.length; ++j) {
  82. if (j > 0) System.out.print(", ");
  83. System.out.print(expTypes[j].getName());
  84. }
  85. System.out.println(";");
  86. }
  87. }
  88. private static void printFields(Class cl) {
  89. Field[] fields = cl.getDeclaredFields();
  90. for (Field f : fields) {
  91. String name = f.getName();
  92. Class type = f.getType();
  93. String modifiers = Modifier.toString(f.getModifiers());
  94. System.out.print("\t");
  95. if (modifiers.length() > 0) System.out.print(modifiers + " ");
  96. System.out.println(type.getName() + " " + name + ";");
  97. }
  98. }
  99. }

在运行时使用反射分析对象

实现通用的toString.

  1. package corejava.reflection;
  2. import java.lang.reflect.AccessibleObject;
  3. import java.lang.reflect.Array;
  4. import java.lang.reflect.Field;
  5. import java.lang.reflect.Modifier;
  6. import java.util.ArrayList;
  7. import java.util.List;
  8. /**
  9. * Created by guolong.fan on 15/4/24.
  10. */
  11. public class ObjectAnalyzer {
  12. /**
  13. * Converts an object to a string representation that lists all fields.
  14. * @param obj an object
  15. * @return a string with the obejct's class name and all fields name and
  16. * values
  17. */
  18. public String toString(Object obj) {
  19. if (obj == null) return "null";
  20. if (visited.contains(obj)) return "...";
  21. visited.add(obj);
  22. Class cl = obj.getClass();
  23. if (cl == String.class) return (String)obj;
  24. if (cl.isArray()) {
  25. String r = cl.getComponentType() + "[]{";
  26. for (int i = 0; i < Array.getLength(obj); ++i) {
  27. if (i > 0) r += ",";
  28. Object val = Array.get(obj, i);
  29. if (cl.getComponentType().isPrimitive()) r += val;
  30. else r += toString(val);
  31. }
  32. return r + "}";
  33. }
  34. String r = cl.getName();
  35. // inspect the fields of this class and all superclasses
  36. do {
  37. r += "[";
  38. Field[] fields = cl.getDeclaredFields();
  39. AccessibleObject.setAccessible(fields, true);
  40. for (Field f : fields) {
  41. if (!Modifier.isStatic(f.getModifiers())) {
  42. if (!r.endsWith("[")) r += ",";
  43. r += f.getName() + "=";
  44. try {
  45. Class t = f.getType();
  46. Object val = f.get(obj);
  47. if (t.isPrimitive()) r += val;
  48. else r += toString(val);
  49. } catch (Exception e) {
  50. e.printStackTrace();
  51. }
  52. }
  53. }
  54. r += "]";
  55. cl = cl.getSuperclass();
  56. } while (cl != null);
  57. return r;
  58. }
  59. private List<Object> visited = new ArrayList<Object>();
  60. public static void main(String[] args) {
  61. ArrayList<Integer> squares = new ArrayList<Integer>();
  62. for (int i = 0; i < 5; ++i) {
  63. squares.add(i * i);
  64. }
  65. System.out.println(new ObjectAnalyzer().toString(squares));
  66. System.out.println(squares);
  67. }
  68. }

使用反射编写泛型数组代码

  1. package corejava.reflection;
  2. import java.lang.reflect.Array;
  3. /**
  4. * Created by guolong.fan on 15/4/24.
  5. */
  6. public class ArrayGrowTest {
  7. public static void main(String[] args) {
  8. int[] a = { 1, 2, 3 };
  9. a = (int[])goodArrayGrow(a);
  10. String[] b = { "Tom", "Dick", "Harry" };
  11. b = (String[]) goodArrayGrow(b);
  12. // Exception in thread "main" java.lang.ClassCastException: [Ljava.lang.Object; cannot be cast to [Ljava.lang.String;
  13. // at corejava.reflection.ArrayGrowTest.main(ArrayGrowTest.java:10)
  14. System.out.println("The following call will generate an exception.");
  15. b = (String[])badArrayGrow(b);
  16. // 要理解这些,需要把泛型数组看成一种类型。Integer[] 和 Object[] 不是一种类型!!!
  17. // 有自己的 Class 对象!!!
  18. Integer[] intArr = new Integer[10];
  19. Object[] objArr = intArr; // OK
  20. // Exception in thread "main" java.lang.ClassCastException: [Ljava.lang.Object; cannot be cast to [Ljava.lang.Integer;
  21. // at corejava.reflection.ArrayGrowTest.main(ArrayGrowTest.java:20)
  22. Object[] objArr2 = new Object[10];
  23. Integer[] intArr2 = (Integer[])objArr2; // Exception
  24. }
  25. /**
  26. * This method attempts to grow an array by alocating a new array and copying all elements.
  27. * @param a the array to grow
  28. * @return a larger array that contains all elements of a. However, the returned array has
  29. * type Object[], not the same type as a.
  30. */
  31. static Object[] badArrayGrow(Object[] a) {
  32. int newLength = a.length * 11 / 10 + 10;
  33. Object[] newArray = new Object[newLength];
  34. System.arraycopy(a, 0, newArray, 0, a.length);
  35. return newArray; // newArray is Object[], not the same type as a.
  36. }
  37. /**
  38. * This method grows an array by allocating a new array of the same type and
  39. * copying all elements.
  40. * @param a the array to grow. This can be an object array or a primitive
  41. * type array
  42. * @return a larger array that contains all elements of a.
  43. */
  44. static Object goodArrayGrow(Object a) {
  45. if (a == null) return null;
  46. Class cl = a.getClass();
  47. if (!cl.isArray()) return null;
  48. Class componentType = cl.getComponentType();
  49. int length = Array.getLength(a); // 获取a的类型
  50. int newLength = length * 11 / 10 + 10;
  51. Object newArray = Array.newInstance(componentType, newLength); // newArray is the same type as a!!
  52. System.arraycopy(a, 0, newArray, 0, length);
  53. return newArray;
  54. }
  55. }

方法指针

Java 没有提供方法指针,但是利用反射可以实现方法指针,但是从设计角度来说,方法指针会来带隐患. interface 是更好的解决方案.

  1. Method m1 = Employee.class.getMethod("getName");
  2. Method m2 = Employee.class.getMethod("raiseSalary", double.class);
  3. Employee e = new Employee();
  4. m1.invoke(e);
  5. m2.invoke(e, 1.0);

示例:

  1. package corejava.reflection;
  2. import java.lang.reflect.InvocationTargetException;
  3. import java.lang.reflect.Method;
  4. /**
  5. * Created by guolong.fan on 15/4/24.
  6. */
  7. public class MethodPointerTest {
  8. public static void main(String[] args) throws NoSuchMethodException {
  9. Method square = MethodPointerTest.class.getMethod("squre", double.class);
  10. printTable(1, 10, 10, square);
  11. }
  12. public static double squre(double x) {
  13. return x * x;
  14. }
  15. private static void printTable(double from, double to, int n, Method f) {
  16. double dx = (to - from) / (n - 1);
  17. for (double x = from; x <= to; x += dx) {
  18. try {
  19. double y = (Double)f.invoke(null, x);
  20. System.out.printf("%10.4f | %10.4f\n", x, y);
  21. } catch (IllegalAccessException e) {
  22. e.printStackTrace();
  23. } catch (InvocationTargetException e) {
  24. e.printStackTrace();
  25. }
  26. }
  27. }
  28. }
添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注