运行时使用反射
上一节中我们已经知道了如何查看任意对象的数据域名称和类型:
- 获得对应的Class对象
- 通过Class对象调用
getDeclaredFields()
那么我们如果想要在程序运行的时候获取数据域的具体值,应该怎么做呢?
问题的关键是使用Filed类的get()
方法,但是因为数据域是私有的,直接去访问这个数据域的话会抛出一个异常,反射机制的默认行为受限于Java的访问控制,如果一个Java程序没有受到安全管理器的控制,就可以覆盖访问控制,为了达到这个目的我们可以使用setAccessible()
方法来做到,具体做法如下:
User user = new User("Li Ming", 20, 1998, 7, 29);
Class userClass = user.getClass();
Filed f = userClass.getDeclaredFiled("name");
f.setAccessible(true);
Object v = f.get(user); // v = "Li Ming"
如果我们希望为这个域赋予一个新值,可以使用f.set(obj, value)
方法将obj对象的f域设置为新值。
使用反射编写泛型数组
java.lang.reflect包中的Array类允许动态的创建数组。这里我们用到了Array类的静态方法newInstance,它能够构造新数组。在调用它的时候必须提供两个参数,一个是数组的元素类型,一个是数组的长度,数组的元素类型用于保证新创建的数组与原数组的类型保持一致。
具体实现如下:
public static Object copyOf(Object a, int newLength) {
Class c1 = a.getClass();
if(!c1.isArray()) {
return null;
}
Class componentType = c1.getComponentType();
int length = Array.getLength(a);
Object newArray = Array.newInstance(componentType, newLength);
System.arraycopy(a, 0, newArray, 0, Math.min(length, newLength));
return newArray;
}
invoke方法
在Method类中有一个invoke方法,它允许调用包装在当前Method对象中的方法。invoke方法的签名是:
Object invoke(Object obj, Object... args);
第一个参数是隐式参数,其余的对象提供了显式参数,对于静态方法的话,第一个参数可以省略,设置为null。
如何得到相应的method对象呢?
这里需要用到Method类中的getMethod方法:
Method getMethod(String name, Class... parameterTypes)
第一个参数是方法的名称,第二个参数是方法的参数类型,这两个结合在一起就可以唯一确定一个方法,然后使用invoke进行调用。
公众号
扫码或微信搜索 Vi的技术博客,关注公众号,不定期送书活动各种福利~