Core Java笔记 3.反射
本章重点:
- Class 类
- 利用反射分析类
- 在运行时使用反射分析对象
- 使用反射编写泛型数组代码
- 方法指针
能够分析类能力的程序称为反射(reflective). Java 提供了丰富且精心设计的工具集(reflection library).
Class 类
在程序运行期间,Java 运行时系统始终为所有的对象维护着一个运行时的类型标识,这个信息保存着每个对象所属的类足迹.
获取 Class 实例.
// 1. 通过实例获得.
Employee e;
Class cl = e.getClass();
// 2. 通过类名获得.
String className = "java.util.Date";
Class cl = Class.forName(className); // need try...catch
// 3. 通过类获得.
Class cl = Date.class
Class cl = int.class
虚拟机为每个类型管理一个Class对象.
if (e.getClass = Employee.class) ...
通过 Class 创建实例.
e.getClass().newInstance(); // 需要有无参构造器
Date.getClass().newInstance();
Class.forName("xxx").newInstance();
利用反射分析类
在
java.lang.reflect
包中的三个核心类: Field、Method、Constructor.
使用反射分析类
package corejava.reflection;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.Scanner;
/**
* Created by guolong.fan on 15/4/24.
*/
public class ReflectionTest {
public static void main(String[] args) {
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):");
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.println(" {");
printConstructors(cl);
System.out.println();
printMethods(cl);
System.out.println();
printFields(cl);
System.out.println("}");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
private static void printConstructors(Class cl) {
Constructor[] constructors = cl.getDeclaredConstructors();
for (Constructor c : constructors) {
String name = c.getName();
System.out.print("\t");
String modifiers = Modifier.toString(c.getModifiers());
if (modifiers.length() > 0) System.out.print(modifiers + " ");
System.out.print(name + "(");
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.print(")");
Class[] expTypes = c.getExceptionTypes();
if (expTypes.length > 0) System.out.print(" throws ");
for (int j = 0; j < expTypes.length; ++j) {
if (j > 0) System.out.print(", ");
System.out.print(expTypes[j].getName());
}
System.out.println(";");
}
}
private static void printMethods(Class cl) {
Method[] methods = cl.getDeclaredMethods();
for (Method m : methods) {
String name = cl.getName();
Class refType = m.getReturnType();
System.out.print("\t");
String modifiers = Modifier.toString(m.getModifiers());
if (modifiers.length() > 0) System.out.print(modifiers + " ");
System.out.print(refType.getName() + " ");
System.out.print(name + "(");
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.print(")");
Class[] expTypes = m.getExceptionTypes();
if (expTypes.length > 0) System.out.print(" throws ");
for (int j = 0; j < expTypes.length; ++j) {
if (j > 0) System.out.print(", ");
System.out.print(expTypes[j].getName());
}
System.out.println(";");
}
}
private static void printFields(Class cl) {
Field[] fields = cl.getDeclaredFields();
for (Field f : fields) {
String name = f.getName();
Class type = f.getType();
String modifiers = Modifier.toString(f.getModifiers());
System.out.print("\t");
if (modifiers.length() > 0) System.out.print(modifiers + " ");
System.out.println(type.getName() + " " + name + ";");
}
}
}
在运行时使用反射分析对象
实现通用的toString
.
package corejava.reflection;
import java.lang.reflect.AccessibleObject;
import java.lang.reflect.Array;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.List;
/**
* Created by guolong.fan on 15/4/24.
*/
public class ObjectAnalyzer {
/**
* Converts an object to a string representation that lists all fields.
* @param obj an object
* @return a string with the obejct's class name and all fields name and
* values
*/
public String toString(Object obj) {
if (obj == null) return "null";
if (visited.contains(obj)) return "...";
visited.add(obj);
Class cl = obj.getClass();
if (cl == String.class) return (String)obj;
if (cl.isArray()) {
String r = cl.getComponentType() + "[]{";
for (int i = 0; i < Array.getLength(obj); ++i) {
if (i > 0) r += ",";
Object val = Array.get(obj, i);
if (cl.getComponentType().isPrimitive()) r += val;
else r += toString(val);
}
return r + "}";
}
String r = cl.getName();
// inspect the fields of this class and all superclasses
do {
r += "[";
Field[] fields = cl.getDeclaredFields();
AccessibleObject.setAccessible(fields, true);
for (Field f : fields) {
if (!Modifier.isStatic(f.getModifiers())) {
if (!r.endsWith("[")) r += ",";
r += f.getName() + "=";
try {
Class t = f.getType();
Object val = f.get(obj);
if (t.isPrimitive()) r += val;
else r += toString(val);
} catch (Exception e) {
e.printStackTrace();
}
}
}
r += "]";
cl = cl.getSuperclass();
} while (cl != null);
return r;
}
private List<Object> visited = new ArrayList<Object>();
public static void main(String[] args) {
ArrayList<Integer> squares = new ArrayList<Integer>();
for (int i = 0; i < 5; ++i) {
squares.add(i * i);
}
System.out.println(new ObjectAnalyzer().toString(squares));
System.out.println(squares);
}
}
使用反射编写泛型数组代码
package corejava.reflection;
import java.lang.reflect.Array;
/**
* Created by guolong.fan on 15/4/24.
*/
public class ArrayGrowTest {
public static void main(String[] args) {
int[] a = { 1, 2, 3 };
a = (int[])goodArrayGrow(a);
String[] b = { "Tom", "Dick", "Harry" };
b = (String[]) goodArrayGrow(b);
// Exception in thread "main" java.lang.ClassCastException: [Ljava.lang.Object; cannot be cast to [Ljava.lang.String;
// at corejava.reflection.ArrayGrowTest.main(ArrayGrowTest.java:10)
System.out.println("The following call will generate an exception.");
b = (String[])badArrayGrow(b);
// 要理解这些,需要把泛型数组看成一种类型。Integer[] 和 Object[] 不是一种类型!!!
// 有自己的 Class 对象!!!
Integer[] intArr = new Integer[10];
Object[] objArr = intArr; // OK
// Exception in thread "main" java.lang.ClassCastException: [Ljava.lang.Object; cannot be cast to [Ljava.lang.Integer;
// at corejava.reflection.ArrayGrowTest.main(ArrayGrowTest.java:20)
Object[] objArr2 = new Object[10];
Integer[] intArr2 = (Integer[])objArr2; // Exception
}
/**
* This method attempts to grow an array by alocating a new array and copying all elements.
* @param a the array to grow
* @return a larger array that contains all elements of a. However, the returned array has
* type Object[], not the same type as a.
*/
static Object[] badArrayGrow(Object[] a) {
int newLength = a.length * 11 / 10 + 10;
Object[] newArray = new Object[newLength];
System.arraycopy(a, 0, newArray, 0, a.length);
return newArray; // newArray is Object[], not the same type as a.
}
/**
* This method grows an array by allocating a new array of the same type and
* copying all elements.
* @param a the array to grow. This can be an object array or a primitive
* type array
* @return a larger array that contains all elements of a.
*/
static Object goodArrayGrow(Object a) {
if (a == null) return null;
Class cl = a.getClass();
if (!cl.isArray()) return null;
Class componentType = cl.getComponentType();
int length = Array.getLength(a); // 获取a的类型
int newLength = length * 11 / 10 + 10;
Object newArray = Array.newInstance(componentType, newLength); // newArray is the same type as a!!
System.arraycopy(a, 0, newArray, 0, length);
return newArray;
}
}
方法指针
Java 没有提供方法指针,但是利用反射可以实现方法指针,但是从设计角度来说,方法指针会来带隐患. interface 是更好的解决方案.
Method m1 = Employee.class.getMethod("getName");
Method m2 = Employee.class.getMethod("raiseSalary", double.class);
Employee e = new Employee();
m1.invoke(e);
m2.invoke(e, 1.0);
示例:
package corejava.reflection;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
/**
* Created by guolong.fan on 15/4/24.
*/
public class MethodPointerTest {
public static void main(String[] args) throws NoSuchMethodException {
Method square = MethodPointerTest.class.getMethod("squre", double.class);
printTable(1, 10, 10, square);
}
public static double squre(double x) {
return x * x;
}
private static void printTable(double from, double to, int n, Method f) {
double dx = (to - from) / (n - 1);
for (double x = from; x <= to; x += dx) {
try {
double y = (Double)f.invoke(null, x);
System.out.printf("%10.4f | %10.4f\n", x, y);
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
}
}
}