原创

【每天十分钟JAVA快速入门】(十七)反射

反射(reflection)

反射是一种功能强大的运行时机制,可以在运行时分析类,操作类成员变量及方法,甚至可以跳过访问修饰符的检查,在构建应用系统底层架构及通用工具类等方面有着广泛的应用。

Class类
Object类中有一个getClass方法,它的返回值是Class,也就是说调用这个方法会返回一个Class类的实例。Class类是对象所属类型的描述。这解释起来有点拗口,来看一个例子就明白了:
Student tom = new Student("Tom","M",9);
System.out.println(tom.getClass().getName());
System.out.println(tom.getName());
分别打印了Student类的名称(包含包名),和Tom。

Class还有一个静态方法forName来根据类名获取该类对应的Class对象:
String className = "java.lang.Math";
Class clazz = Class.forName(className);
如果类名不存在就会抛出ClassNotFoundException

还有一种更简单的获取Class对象的方法,任意的Java类型T,使用T.class即可。这里的T可以不是一个类,可以是基本数据类型,数组,甚至是void。

每种类型在虚拟机中只有一个Class对象,因此可以使用==来判断两个Class对象是否相同:
Student tom = new Student("Tom","M",9);
Student jerry = new Student("Jerry","M",9);
System.out.println(tom.getClass() == jerry.getClass());
Class类的newInstance方法调用对应类的无参构造器实例化一个类,如果该类没有无参构造器则会抛出异常:
Object o = Class.forName(className).newInstance();

Class类中的getFields,getMethods,getConstructors方法分别返回类的public成员变量、方法和构造器数组,包括超类的公有成员。
Class类中的getDeclaredFields,getDeclaredMethods,getDeclaredConstructors方法分别返回类的全部成员变量、方法和构造器数组,但不包括超类的成员。

Field,Method,Constructor,Modifier
java.lang.refelct包下的Field,Method,Constructor类分别用于描述类的成员变量,方法和构造器,例如:
Student tom = new Student("Tom","M",9);
Field field = tom.getClass().getDeclaredField("name");
String name = (String)field.get(tom);
实际上这里的代码运行不了,因为name是private的,只能使用getName方法来访问,例如:
Student tom = new Student("Tom","M",9);
Method method = tom.getClass().getDeclaredMethod("getName");
String name = (String)method.invoke(tom);
当然反射机制十分强大,我们在一开始就提到它可以绕过访问修饰符的限制,例如上面的name虽然是private的,但是可以通过setAccessible方法强制设置访问权限,例如:
field.setAccessible(true);

Modifier类用来描述修饰符,例如可以使用isPublic、isPrivate 或 isFinal 来判断方法或构造器是否是 public、 private 或 final,还有isAbstract、isStatic等等其他和修饰符有关的方法可以使用。

反射很强大,可以动态地分析和操作类成员变量及方法,同时反射也很脆弱,很多错误只能在运行时才会产生,在编译阶段很难给出错误提示,因此在一般的编写程序过程中反射不宜过多使用。
正文到此结束