能够分析类能力的程序称为反射(reflective)。反射机制的功能极其强大,在反射机制可以用来:

  • 在运行时分析类的能力。
  • 在运行时查看对象,例如,编写一个 toString 方法供所有类使用。
  • 实现通用的数组操作代码。
  • 利用 Method 对象,这个对象很像 C++ 中的函数指针。

    Class 类

    在程序运行期间,Java 运行时系统始终为所有的对象维护一个被称为运行时的类型标识。这个信息跟踪着每个对象所属的类。保存这些信息的类被称为 Class。
    Class 类的一些方法: ``` Employee e; // 直接调用 Object 类中的 getClass() Class cl = e.getClass(); cl.getName(); // Employee

// 可以调用静态方法来获得类名对应的 Class 对象 String classname = “java.util.Random”; Class cl = Class.forName(classname);

// 直接使用 T.class Class cl = Random.class; Class cl = int.class;

// 虚拟机为每个类型管理一个 Class 对象。因此,可以利用 == 运算符实现两个类对象比较的操作 if (e.getClass() == Employee.class) {…}

// 可以使用 newInstance(),动态的获得一个类的实例 e.getClass().newInstance(); // 当然只能调用无参构造器,没有无参构造器就会抛出异常

  1. > Class 类实际上是一个泛型类
  2. ### 捕获异常
  3. 当程序运行过程中发生错误时,就会 **抛出异常**。抛出异常比终止程序要灵活得多,这是因为可以提供一个**捕获**异常的处理器(handler)对异常情况进行处理。<br />异常有两种类型:
  4. - 未检查异常:编译器不会查看是否为这些错误提供了处理器,比如,null 引用。
  5. - 已检查异常:编译器会检查是否提供了处理器
  6. 将可能抛出已检查异常的一个或多个方法调用代码放在 try 块中,然后在 catch 子句中提供处理器代码:

try { String name = “java.util.Random”; Class cl = Class.forName(name); // might throw excpetion … } catch (Exception e) { e.printStackTrace(); }

  1. ### 利用反射分析类的能力
  2. 使用 java.lang.reflect 包中的三个类:Field, Method Constructor 就能来分析一个类中的全部域、方法和构造器。再加上 Modifier 类,就可以将修饰符也显式出来。

import java.util.; import java.lang.reflect.;

public class Main { public static void main(String[] args) { // read class name from command line args or user input String name; if (args.length > 0) name = args[0]; else { Scanner in = new Scanner(System.in); System.out.println(“Enter class name (e.g. java.util.Date): “); // like java.lang.Double name = in.next(); }

  1. try
  2. {
  3. // print class name and superclass name (if != Object)
  4. Class cl = Class.forName(name);
  5. Class supercl = cl.getSuperclass();
  6. String modifiers = Modifier.toString(cl.getModifiers());
  7. if (modifiers.length() > 0) System.out.print(modifiers + " ");
  8. System.out.print("class " + name);
  9. if (supercl != null && supercl != Object.class) System.out.print(" extends " + supercl.getName());
  10. System.out.print("\n{\n");
  11. printConstructors(cl);
  12. System.out.println();
  13. printMethods(cl);
  14. System.out.println();
  15. printFields(cl);
  16. System.out.println("}");
  17. }
  18. catch (ClassNotFoundException e)
  19. {
  20. e.printStackTrace();
  21. }
  22. System.exit(0);

}

/**

  1. * Prints all constructors of a class
  2. * @param cl a class
  3. */

public static void printConstructors(Class cl) { Constructor[] constructors = cl.getDeclaredConstructors();

  1. for (Constructor c : constructors)
  2. {
  3. String name = c.getName();
  4. System.out.print(" ");
  5. String modifiers = Modifier.toString(c.getModifiers());
  6. if (modifiers.length() > 0) System.out.print(modifiers + " ");
  7. System.out.print(name + "(");
  8. // print parameter types
  9. Class[] paramTypes = c.getParameterTypes();
  10. for (int j = 0; j < paramTypes.length; j++)
  11. {
  12. if (j > 0) System.out.print(", ");
  13. System.out.print(paramTypes[j].getName());
  14. }
  15. System.out.println(");");
  16. }

}

/**

  1. * Prints all methods of a class
  2. * @param cl a class
  3. */

public static void printMethods(Class cl) { Method[] methods = cl.getDeclaredMethods();

  1. for (Method m : methods)
  2. {
  3. Class retType = m.getReturnType();
  4. String name = m.getName();
  5. System.out.print(" ");
  6. // print modifiers, return type and method name
  7. String modifiers = Modifier.toString(m.getModifiers());
  8. if (modifiers.length() > 0) System.out.print(modifiers + " ");
  9. System.out.print(retType.getName() + " " + name + "(");
  10. // print parameter types
  11. Class[] paramTypes = m.getParameterTypes();
  12. for (int j = 0; j < paramTypes.length; j++)
  13. {
  14. if (j > 0) System.out.print(", ");
  15. System.out.print(paramTypes[j].getName());
  16. }
  17. System.out.println(");");
  18. }

}

/**

  1. * Prints all fields of a class
  2. * @param cl a class
  3. */

public static void printFields(Class cl) { Field[] fields = cl.getDeclaredFields();

  1. for (Field f : fields)
  2. {
  3. Class type = f.getType();
  4. String name = f.getName();
  5. System.out.print(" ");
  6. String modifiers = Modifier.toString(f.getModifiers());
  7. if (modifiers.length() > 0) System.out.print(modifiers + " ");
  8. System.out.println(type.getName() + " " + name + ";");
  9. }

} }

  1. ### 在运行时使用反射分析对象
  2. 在运行的过程中,我们可以通过反射查看数据域中的实际内容:

Employee employee = new Employee(“yikang”, 132465, 1998, 9, 18); Class cl = employee.getClass(); Field field = cl.getDeclaredField(“name”); field.setAccessible(true); // 设置访问私有权限 Object v = field.get(employee); System.out.println(v); // “yikang”

field.set(employee, “kang”); System.out.println(employee.getName());

  1. ### 利用反射编写泛型数组代码
  2. 通过 Class 确定数组类型类进行相应的泛型编写:

public static Object CopyOf(Object a, int newLength) { Class cl = a.getClass(); if (!cl.isArray()) return null; Class componentType = cl.getComponentType(); int length = Array.getLength(a); Object newArray = Array.newInstance(componentType, newLength); System.arraycopy(a, 0, newArray, 0, Math.min(length, newLength)); return newArray; }

  1. ### 调用任意方法
  2. 使用 Method 中的 `invoke()` 来调用对应的方法。当然,要先得到 Method 对象:

Employee employee = new Employee(“yikang”, 123456, 1998, 11, 5); Method m1 = Employee.class.getMethod(“getName”); Method m2 = Employee.class.getMethod(“getSalary”); Method m3 = Employee.class.getMethod(“raiseSalary”, double.class);

m3.invoke(employee, 50); String n = (String) m1.invoke(employee); // yikang double s = (Double) m2.invoke(employee); // 185184

```