前面已经通过Class类获得对应类的构造方法,一旦获取了对应类的构造方法,很自然地就会想到通过这些构造方法创建出这些对应类的实例对象,之后再通过这些对象完成程序需要实现的目标。接下来继续通过案例来演示如何实例化对象。
为了方便演示,用来测试的对应类Super的代码调整如下:
编译、运行程序,通过Class类的newInstance()方法创建Super对象(需要强制类型转换),然后调用这个对象的supPublic()方法,输出结果为4。
到目前为止,似乎可以看出点反射机制的端倪—可以根据用户运行时输入的信息,动态创建不同的对象,再调用对象的方法执行相关的功能。
通过Class类的newInstance()方法创建对象,该方法要求该Class对应类有无参构造方法。执行newInstance()方法实际上就是使用对应类的无参构造方法来创建该类的实例,其代码等价于:
如果Super类没有无参构造方法,运行程序时则会出现如图5.11所示的问题,抛出一个InstantiationException实例化异常。
图5.11 newInstance()方法产生实例化异常
如果要想使用有参构造方法创建对象,则需要先通过Class对象获取指定的Constructor对象,再调用Constructor对象的newInstance(Object[] args)方法来创建该Class对象对应类的实例。具体代码如下:
编译、运行程序,输出结果为22和3.0。需要注意的是,通过Class对象获得指定Constructor对象的方法getDeclaredConstructor((Class[] args))中,参数列表为Class类数组。本例中直接使用new Class[]{int.class,int.class}语句创建了这个Class类数组,表示需要获取的构造方法内含有两个int型的形参。之后调用Constructor的newInstance(Object[] args)方法创建对象时,输入参数为Object对象数组,本例中直接使用new Object[]{21, 22}创建了此对象数组。
通过 Constructor 的 newInstance()方法,也可以创建无参对象,这样在调用getDeclaredConstructor((Class[] args))和newInstance(Object[] args)方法时,参数列表为空即可。
还是上面的Super类,其中有一个整型的私有属性supPri,初始值为1。因为Super类并没有提供针对supPri这个属性的公有的getter和setter方法,所以在这个类外,以现有的知识是无法获得并修改这个属性值的。接下来通过Java反射机制提供的Field类,实现在程序运行时修改类中私有属性值的功能。具体代码如下:
代码中,首先通过Class对象的getDeclaredField(“supPri”)方法获得了Field对象f,然后通过f.setAccessible(true)方法取消了supPri属性的访问控制权限(只是取消Field对象f对应属性supPri的访问控制权限,在Field对象内部起作用,仍不可以通过sup.supPri直接进行访问),之后再通过set(Object o,Object v)、get(Object o),修改、获取该属性的值。编译、运行程序,运行结果如图5.12所示。
图5.12 通过Field对象修改私有属性
通过反射机制,运行时可以根据用户的输入创建不同的对象,并且可以修改属性的访问控制权限及属性值。接下来将介绍使用反射机制,通过调用Method类的一些方法,动态执行Class对应类的方法。
前面介绍使用反射机制创建对象时,程序可以根据用户的输入动态创建一个对象。假设现在有这样的需求,需要在程序运行时,根据用户提供的方法名称、参数个数、参数类型,动态调用不同的方法完成不同的功能。
例如TestInvokeMethod类中有四个方法,public int add(int x, int y)、public int add(int x)、public int multiply(int x, int y)、public int multiply(int x),分别实现的功能是求和、加一、求乘积、求平方四个功能。程序运行时,用户输入方法和实参列表,程序动态调用对应的方法,将结果反馈给用户。具体代码如下(因为篇幅原因,程序中直接给出了方法和实参列表,没有要求用户输入):
程序运行时获得方法名multiply以及实参列表3和4,通过getDeclaredMethod (“multiply”,new Class[]{int.class, int.class})方法获得Method对象m,再通过m.invoke(obj, newObject[]{3,4})方法调用对象obj(可能也是通过反射机制动态创建的)对应方法public int multiply(int x, int y)取得需要的结果。程序如果获得的方法名为add,参数列表为18,则反射机制的动态方法调用会执行对象的public int add(int x)方法。程序运行结果如图5.13所示。
至此,反射机制的核心内容已介绍完毕。其中根据用户的输入,使用反射机制动态创建对象,动态调用方法是Java反射机制的精髓,学习它对后期框架课程的深入理解很有帮助。