能够分析类能力的程序称为反射(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(); // 当然只能调用无参构造器,没有无参构造器就会抛出异常
> Class 类实际上是一个泛型类
### 捕获异常
当程序运行过程中发生错误时,就会 **抛出异常**。抛出异常比终止程序要灵活得多,这是因为可以提供一个**捕获**异常的处理器(handler)对异常情况进行处理。<br />异常有两种类型:
- 未检查异常:编译器不会查看是否为这些错误提供了处理器,比如,null 引用。
- 已检查异常:编译器会检查是否提供了处理器
将可能抛出已检查异常的一个或多个方法调用代码放在 try 块中,然后在 catch 子句中提供处理器代码:
try { String name = “java.util.Random”; Class cl = Class.forName(name); // might throw excpetion … } catch (Exception e) { e.printStackTrace(); }
### 利用反射分析类的能力
使用 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(); }
try
{
// print class name and superclass name (if != Object)
Class cl = Class.forName(name);
Class supercl = cl.getSuperclass();
String modifiers = Modifier.toString(cl.getModifiers());
if (modifiers.length() > 0) System.out.print(modifiers + " ");
System.out.print("class " + name);
if (supercl != null && supercl != Object.class) System.out.print(" extends " + supercl.getName());
System.out.print("\n{\n");
printConstructors(cl);
System.out.println();
printMethods(cl);
System.out.println();
printFields(cl);
System.out.println("}");
}
catch (ClassNotFoundException e)
{
e.printStackTrace();
}
System.exit(0);
}
/**
* Prints all constructors of a class
* @param cl a class
*/
public static void printConstructors(Class cl) { Constructor[] constructors = cl.getDeclaredConstructors();
for (Constructor c : constructors)
{
String name = c.getName();
System.out.print(" ");
String modifiers = Modifier.toString(c.getModifiers());
if (modifiers.length() > 0) System.out.print(modifiers + " ");
System.out.print(name + "(");
// print parameter types
Class[] paramTypes = c.getParameterTypes();
for (int j = 0; j < paramTypes.length; j++)
{
if (j > 0) System.out.print(", ");
System.out.print(paramTypes[j].getName());
}
System.out.println(");");
}
}
/**
* Prints all methods of a class
* @param cl a class
*/
public static void printMethods(Class cl) { Method[] methods = cl.getDeclaredMethods();
for (Method m : methods)
{
Class retType = m.getReturnType();
String name = m.getName();
System.out.print(" ");
// print modifiers, return type and method name
String modifiers = Modifier.toString(m.getModifiers());
if (modifiers.length() > 0) System.out.print(modifiers + " ");
System.out.print(retType.getName() + " " + name + "(");
// print parameter types
Class[] paramTypes = m.getParameterTypes();
for (int j = 0; j < paramTypes.length; j++)
{
if (j > 0) System.out.print(", ");
System.out.print(paramTypes[j].getName());
}
System.out.println(");");
}
}
/**
* Prints all fields of a class
* @param cl a class
*/
public static void printFields(Class cl) { Field[] fields = cl.getDeclaredFields();
for (Field f : fields)
{
Class type = f.getType();
String name = f.getName();
System.out.print(" ");
String modifiers = Modifier.toString(f.getModifiers());
if (modifiers.length() > 0) System.out.print(modifiers + " ");
System.out.println(type.getName() + " " + name + ";");
}
} }
### 在运行时使用反射分析对象
在运行的过程中,我们可以通过反射查看数据域中的实际内容:
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());
### 利用反射编写泛型数组代码
通过 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; }
### 调用任意方法
使用 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
```