java核心技术之反射
能够分析类能力的程序成为反射。
使用反射的主要对象是工具构造者,而非应用程序员。
1、Class
返回Class类得实例有几种方式:
//a Girl g1 = new Girl(); Class c0 = g1.getClass(); //b String className = "com.gong.reflect.Girl"; Class c1 = Class.forName(className); //c Class c2 = Girl.class;?
2、检查类结构
检查类结构--java反射机制的重要内容
java.lang.reflect包中三个类Field、Method、Constructor分别用于描述类得域、方法和构造器。
public class ReflectionTest { 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): "); name = in.next(); } try { Class cl = Class.forName(name); Class supercl = cl.getSuperclass(); String modifiers = Modifier.toString(cl.getModifiers()); //getModifiers()返回一个描述构造器、方法或域的修饰符的整型数值 System.out.println(cl.getModifiers()); //Modifier.toString返回对应modifier位设置的修饰符的字符串表示 System.out.println("modifiers:"+modifiers); 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); } 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(");"); } } 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(");"); } } 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 + ";"); } }}?
3、运行时反射分析对象
反射机制的默认行为受限于java访问控制。
public class FieldTest { public static void main(String[] args) { try { Girl g = new Girl("lady gaga", 26, 38); Class cl = g.getClass(); Field f = cl.getDeclaredField("name"); //为反射对象设置可访问标志 //true表示屏蔽java语言检查,对象的私有属性也可以被查询和设置 f.setAccessible(true); Object o = f.get(g); System.out.println(o); }catch(SecurityException e) { e.printStackTrace(); }catch(NoSuchFieldException e) { e.printStackTrace(); }catch(IllegalArgumentException e) { e.printStackTrace(); }catch(IllegalAccessException e) { e.printStackTrace(); } }}?
4、利用反射编写通用数组代码
java.lang.reflect包中的Array类允许动态地创建数组。
public class ArrayGrowTest { public static void main(String[] args) { int[] a = { 1, 2, 3 }; a = (int[]) goodArrayGrow(a); arrayPrint(a); String[] b = { "Tom", "Dick", "Harry" }; b = (String[]) goodArrayGrow(b); arrayPrint(b); System.out.println("The following call will generate an exception."); b = (String[]) badArrayGrow(b); } static Object[] badArrayGrow(Object[] a) { int newLength = a.length * 11 / 10 + 10; //新创建的对象数组不能转成String数组 Object[] newArray = new Object[newLength]; System.arraycopy(a, 0, newArray, 0, a.length); return newArray; } static Object goodArrayGrow(Object a) { Class cl = a.getClass(); if (!cl.isArray()) return null; Class componentType = cl.getComponentType(); int length = Array.getLength(a); int newLength = length * 11 / 10 + 10; //componentType数组元素类型,newLength数组的长度 Object newArray = Array.newInstance(componentType, newLength); System.arraycopy(a, 0, newArray, 0, length); return newArray; } static void arrayPrint(Object a) { Class cl = a.getClass(); if (!cl.isArray()) return; Class componentType = cl.getComponentType(); int length = Array.getLength(a); System.out.print(componentType.getName() + "[" + length + "] = { "); for (int i = 0; i < Array.getLength(a); i++) System.out.print(Array.get(a, i) + " "); System.out.println("}"); }}?
5、方法指针
执行对象方法或静态方法
public class MethodPointerTest { public static void main(String[] args) throws Exception { Method square = MethodPointerTest.class.getMethod("square", double.class); Method sqrt = Math.class.getMethod("sqrt", double.class); printTable(1, 10, 10, square); printTable(1, 10, 10, sqrt); } public static double square(double x) { return x * x; } public static void printTable(double from, double to, int n, Method f) { System.out.println(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 (Exception e) { e.printStackTrace(); } } }}
建议在必要的时候才使用Method对象,最好使用接口和内部类。
不要过多使用反射
反射很脆弱,编译器很难帮助发现程序中的错误。任何错误只能在运行时发现,并导致异常。