
1.4 反射
在Java语言中,反射机制是指对于处在运行状态中的类,都能够获取到这个类的所有属性和方法。对于任意一个对象,都能够调用它的任意一个方法以及访问它的属性;这种通过动态获取类或对象的属性以及方法从而完成调用功能被称为Java语言的反射机制。它主要实现了以下功能:
• 获取类的访问修饰符、方法、属性以及父类信息。
• 在运行时根据类的名字创建对象。可以在运行时调用任意一个对象的方法。
• 在运行时判断一个对象属于哪个类。
• 生成动态代理。
在反射机制中Class是一个非常重要的类,在Java语言中获取Class对象主要有如下几种方法。
1)通过className.class来获取:


程序的运行结果为:

2)通过Class.forName()来获取:

程序的运行结果为:

3)通过Object.getClass()来获取:

程序的运行结果为:

从上面的例子可知,虽然这三种方式都可以获得类的Class对象,但是它们还是有区别的,主要区别如下所示:
• 方法1)不执行静态块和动态构造块;
• 方法2)只执行静态块,而不执行动态构造块;
• 方法3)因为需要创建对象,所以会执行静态块和动态构造块。
Class类提供了非常多的方法,下面给出三类常用的方法。
(1)获取类的构造方法
构造方法的封装类为Constructor,Class类中有如下四个方法来获得Constructor对象:
1)public Constructor<?>[] getConstructors():返回类的所有的public构造方法;
2)public Constructor<T>getConstructor(Class<?>... parameterTypes):返回指定的public构造方法;
3)public Constructor<?>[] getDeclaredConstructors():返回类的所有的构造方法;
4)public Constructor<T>getDeclaredConstructor(Class<?>... parameterTypes):返回指定的构造方法。
(2)获取类的成员变量的方法
成员变量的封装类为Field类,Class类提供了以下四个方法来获取Field对象:
1)public Field[] getFields():获取类的所有public成员变量;
2)public Field getField(String name):获取指定的public成员变量;
3)public Field[] getDeclaredFields():获取类的所有成员变量;
4)public Field getDeclaredField(String name):获取任意访问权限的指定名字的成员变量。
(3)获取类的方法
1)public Method[] getMethods();
2)public Method getMethod(String name,Class<?>... parameterTypes) public Method[];
3)getDeclaredMethods():获取所有的方法;
4)public Method getDeclaredMethod(String name,Class<?>... parameterTypes)。
使用示例如下所示:

程序的运行结果为:


引申:有如下代码:

现给定一个ReadOnlyClass的对象roc,能否把这个对象的age值改成30?
答案:从正常编程的角度出发分析,会发现在本题中,age属性被修饰为private,而且这个类只提供了获取age的public的方法,而没有提供修改age的方法,因此,这个类是一个只读的类,无法修改age的值。但是Java语言还有一个非常强大的特性:反射机制,所以本题中,可以通过反射机制来修改age的值。
在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取对象的信息以及动态调用对象的方法的功能称为Java语言的反射机制。Java反射机制允许程序在运行时加载、探知和使用编译期间完全未知的class。换句话说,Java可以加载一个运行时才得知名称的class,获得其完整结构。
在Java语言中,任何一个类都可以得到对应的Class实例,通过Class实例就可以获取类或对象的所有信息,包括属性(Field对象)、方法(Method对象)或构造方法(Constructor对象)。对于本题而言,在获取到ReadOnlyClass类的Class实例以后,就可以通过反射机制获取到age属性对应的Field对象,然后可以通过这个对象来修改age的值,实现代码如下所示:

程序的运行结果为:
