250 likes | 438 Views
java 的反射机制. 反射 类动态装入与检查 使用反射生成与使用对象. 在 Java 运行时环境中,对于任意一个类,能否知道这个类有哪些属性和方法?对于任意一个对象,能否调用它的任意一个方法?答案是肯定的。这种动态获取类的信息,以及动态调用对象的方法的功能来自于 Java 语言的反射( Reflection )机制。 Java 反射机制主要提供了以下功能: ◆在运行时判断任意一个对象所属的类; ◆在运行时构造任意一个类的对象; ◆在运行时判断任意一个类所具有的成员变量和方法; ◆在运行时调用任意一个对象的方法; ◆生成动态代理。.
E N D
java 的反射机制 • 反射 • 类动态装入与检查 • 使用反射生成与使用对象
在Java运行时环境中,对于任意一个类,能否知道这个类有哪些属性和方法?对于任意一个对象,能否调用它的任意一个方法?答案是肯定的。这种动态获取类的信息,以及动态调用对象的方法的功能来自于Java语言的反射(Reflection)机制。Java反射机制主要提供了以下功能:在Java运行时环境中,对于任意一个类,能否知道这个类有哪些属性和方法?对于任意一个对象,能否调用它的任意一个方法?答案是肯定的。这种动态获取类的信息,以及动态调用对象的方法的功能来自于Java语言的反射(Reflection)机制。Java反射机制主要提供了以下功能: • ◆在运行时判断任意一个对象所属的类;◆在运行时构造任意一个类的对象;◆在运行时判断任意一个类所具有的成员变量和方法;◆在运行时调用任意一个对象的方法;◆生成动态代理。
在JDK中,主要由以下类来实现Java反射机制,这些类都位于java.lang.reflect包中。在JDK中,主要由以下类来实现Java反射机制,这些类都位于java.lang.reflect包中。 • ◆Class类:代表一个类。◆Field类:代表类的成员变量(成员变量也称为类的属性)。◆Method类:代表类的方法。◆Constructor类:代表类的构造方法。◆Array类:提供了动态创建数组,以及访问数组元素的静态方法。
Class与类动态装入 • 当真正需要使用一個类时系统才会装入它 • java.lang.Class是Java应用程序在运行时装入类和接口的实例 • Class只能由系统建立对象 • 我们可以通过Object的getClass()方法來取得某个对象对应Class对象
String name = "hello"; Class stringClass = name.getClass(); System.out.println("类名:" + stringClass.getName()); System.out.println("是否为接口:" + stringClass.isInterface()); System.out.println("是否为基本类型:" + stringClass.isPrimitive()); System.out.println("是否为数组:" + stringClass.isArray()); System.out.println("父类名:" + stringClass.getSuperclass().getName()); Class stringClass = String.class;
Class的信息是在编译时确定的 • 执行时JVM在使用某个类时,会先检查对应的Class对象是否装入 • 如果沒有装入,则会寻找对应的.class档案并装入
一个类在JVM中只会有一个Class实例 • 每个类的实例都会记得自己是由哪个Class实例所生成 • 可使用getClass()或.class来取得Class实例
import java.lang.reflect.*;public class DumpMethods {public static void main(String args[]) throws Exception{//加载并初始化命令行参数指定的类 Class classType = Class.forName(args[0]);//获得类的所有方法Method methods[] = classType.getDeclaredMethods();for(int i = 0; i < methods.length; i++)System.out.println(methods[i].toString());}}
数组是对象,也有其对应的Class实例 System.out.println(boolean.class); System.out.println(void.class); int[] iarr = new int[10]; System.out.println(iarr.getClass().toString()); double[] darr = new double[10]; System.out.println(darr.getClass().toString()); boolean void class [I class [D
从Class中获得信息 • Class表示所装入的类,取得Class之后,就可以取得该类相关信息 • 包对应的是java.lang.Package • 构造方法的对应的是java.lang.reflect.Constructor • 成员方法对应的是java.lang.reflect.Method • 属性对应的是java.lang.reflect.Field
try { Class c = Class.forName(args[0]); Package p = c.getPackage(); System.out.println(p.getName()); } catch(ArrayIndexOutOfBoundsException e) { System.out.println("没有指定类"); } catch(ClassNotFoundException e) { System.out.println("找不到指定类"); }
Class c = Class.forName(args[0]); Package p = c.getPackage(); System.out.printf("package %s;%n", p.getName()); // 取得类型修饰,是否是class、interface int m = c.getModifiers(); System.out.print(Modifier.toString(m) + " "); // 如果是接口 if(Modifier.isInterface(m)) { System.out.print("interface "); } else { System.out.print("class "); } System.out.println(c.getName() + " {");
// 获得声明的成员 Field[] fields = c.getDeclaredFields(); for(Field field : fields) { // 显示权限修饰,如public、protected、private System.out.print("\t" + Modifier.toString(field.getModifiers())); // 显示名称 System.out.print(" " + field.getType().getName() + " "); // 输出成员名称 System.out.println(field.getName() + ";"); }
// 获得构造方法 Constructor[] constructors = c.getDeclaredConstructors(); for(Constructor constructor : constructors) { // 输出控制修饰public、protected、private System.out.print("\t" + Modifier.toString( constructor.getModifiers())); // 输出名称 System.out.println(" " + constructor.getName() + "();"); }
// 获得成员函数 Method[] methods = c.getDeclaredMethods(); for(Method method : methods) { System.out.print("\t" + Modifier.toString( method.getModifiers())) System.out.print(" " + method.getReturnType().getName() + " "); System.out.println(method.getName() + "();"); }
动态生成对象 • 使用Class的newInstance()方法來实例化一个对象 Class c = Class.forName(args[0]); List list = (List) c.newInstance(); for(int i = 0; i < 5; i++) { list.add("element " + i); } for(Object o: list.toArray()) { System.out.println(o); }
如果要动态加载并生成对象,则须指定初始参数如果要动态加载并生成对象,则须指定初始参数 • 要先指定参数类型 • 取得构造方法 • 使用Constructor的newInstance()并指定参数后生成实例
动态生成对象 Class c = Class.forName(args[0]); // 指定参数类型 Class[] params = new Class[2]; // 第一个参数是String params[0] = String.class; // 第二个参数是int params[1] = Integer.TYPE; // 取得对应参数的构造方法 Constructor constructor = c.getConstructor(params); // 指定参数的值 Object[] argObjs = new Object[2]; argObjs[0] = "zhang"; argObjs[1] = new Integer(20); // 生成实例 Object obj = constructor.newInstance(argObjs);
小结 在java.lang.Object类中定义了getClass()方法,因此对于任意一个Java对象,都可以通过此方法获得对象的类型。Class类是Reflection API中的核心类,它有以下方法。 ◆getName():获得类的完整名字。◆getFields():获得类的public类型的属性。◆getDeclaredFields():获得类的所有属性。◆getMethods():获得类的public类型的方法。◆getDeclaredMethods():获得类的所有方法。◆getMethod(String name, Class[] parameterTypes):获得类的特定方法,name参数指定方法的名字,parameterTypes参数指定方法的参数类型。◆getConstrutors():获得类的public类型的构造方法。◆getConstrutor(Class[] parameterTypes):获得类的特定构造方法,parameterTypes参数指定构造方法的参数类型。◆newInstance():通过类的不带参数的构造方法创建这个类的一个对象。
执行方法 • 使用invoke()方法来动态执行指定的方法
Class c = Class.forName(args[0]); // 使用无参数的构造方法建立对象 Object targetObj = c.newInstance(); // 指定参数类型 Class[] param1 = {String.class}; // 根据参数获得对应方法 Method setNameMethod = c.getMethod("setName", param1); // 设定参数值 Object[] argObjs1 = {"wang"}; // 运行方法 setNameMethod.invoke(targetObj, argObjs1); Class[] param2 = {Integer.TYPE}; Method setScoreMethod = c.getMethod("setScore", param2); Object[] argObjs2 = {new Integer(90)}; setScoreMethod.invoke(targetObj, argObjs2); System.out.println(targetObj);
私有方法的例子 Method privateMethod = c.getDeclaredMethod("somePrivateMethod", new Class[0]); privateMethod.setAccessible(true); privateMethod.invoke(targetObj, argObjs);
修改成员值 Class c = Class.forName(args[0]); Object targetObj = c.newInstance(); Field testInt = c.getField("testInt"); testInt.setInt(targetObj, 99); Field testString = c.getField("testString"); testString.set(targetObj, "caterpillar"); System.out.println(targetObj); Field privateField = c.getDeclaredField("privateField"); privateField.setAccessible(true); privateField.setInt(targetObj, 99);
安全性和反射 • 在处理反射时安全性是一个较复杂的问题。反射经常由框架型代码使用,可能希望框架能够全面接入代码,无需考虑常规的接入限制。但是,不受控制的接入会带来严重的安全性风险。 • 由于这些互相矛盾的需求,Java编程语言定义一种多级别方法来处理反射的安全性。