java.lang.array提供了动态创建和当问数组元素的各种静态方法。
public class ArrayTest2 {
/*
* 动态创建一个5X10X15的三维数组并且设置[3][5][10]位置的值
*/
public static void main(String[] args) {
//设置维数数组,即将数组的维数存到一个数组中
int[] dims = new int[]{5, 10, 15};
//利用Array的静态方法newInstance传递数组中元素的Class类型以及维数数组动态生成一个数组对象
Object array = Array.newInstance(Integer.TYPE, dims);
//多维数组大家都知道,即数组的数组的数组的...这里是三维数组,取出数组中3这个索引的值其实是一个二维数组
Object arrayObj = Array.get(array, 3);
//得到该二维数组的类型
Class cls = arrayObj.getClass().getComponentType();
//继续得到二维数组中索引5对应的一维数组
arrayObj = Array.get(arrayObj, 5);
//设置该一维数组中索引10的位置的值为120
Array.set(arrayObj, 10, 120);
//将Object类型的数组对象array强制转化为int[][][]
int[][][] intArray = (int[][][]) array;
System.out.println(intArray[3][5][10]);
}
}
为一个class生成对应的Class对象:
如果要生成对象实体 ,在反射动态机制中有两种方法,一个针对”无自变量构造方法“,另外一个针对”带参数的构造方法“,如果调用的是”带参数构造方法“需要调用Constructor对象的newInstance(),并且需要首先准备一个Class[]作为Constructor的参数类型,然后以此为自变量调用getConstructor(),获得一个专属的Construtor,再调用该Construtor的newInstance()。如果调用无自变量的构造方法,直接调用Class的newInstance()就可以。
运行时调用Method:和动态调用带参数的构造方法类似,首先需要准备一个Class[]作为参数类型,接着以此为自变量调用getMethod(),获得特定的Metho0d Object。接下来准备一个Object[]放置自变量,调用上面得到Method对象的invoke方法。
那么为什么获得Method Object时不需要指定返回类型呢?
因为Method overloading机制要求signature必须唯一,而返回类型并非signature的一个成分。换句话说,只要制定了method名称和参数列,就一定指出了一个独一无二的method。
代码:
和调用某个特定构造方法构造类的实例以及调用某个特定的方法不同,变更"field"内容 不需要参数和自变量。首先调用Class的getField()并制定field名称。获得特定的Field Object之后便可以直接调用Field的get()和set()。
代码:
可以在一个类中修改另一个类中的私有成员变量吗?
呵呵,如果你是一位rookie,相信你一定会说不可以,其实通过反射机制是可以修改的,先看看下面两个方法:
<!-- Generated by javadoc (build 1.6.0) on Wed Nov 29 02:21:23 PST 2006 -->
Field |
|
Field | getField (String name) Returns a Field object that reflects the specified public member field of the class or interface represented by this Class object. |
还要看看另外一个关键的类:
public class AccessibleObject extends Object implements AnnotatedElement
<!-- Generated by javadoc (build 1.6.0) on Wed Nov 29 02:21:29 PST 2006 -->
The AccessibleObject class is the base class for Field, Method and Constructor objects. It provides the ability to flag a reflected object as suppressing default Java language access control checks when it is used. The access checks --for public, default (package) access, protected, and private members--are performed when Fields, Methods or Constructors are used to set or get fields, to invoke methods, or to create and initialize new instances of classes, respectively.
从上面可以看出,AccessibleObject类是Field,Method和Constructor的基类,使用它可以提供对JAVA语言访问控制检查的一种”压制“,访问检查大家都应该很清楚,是指对于public, default (package) , protected, private修饰的成员,当设置或者获取字段的值,调用方法,或者是创建一个类的实例时进行的一种访问控制检查,因为大家都知道上面四种访问修饰符都有自己的访问权限,访问检查便提供了对这些访问权限的检查。
但是AccessibleObject提供了对访问控制检查的一种压制能力,也就是说,利用它可以设置或者取消这种访问检测能力。
再看看下面的这个方法:
public void setAccessible(boolean flag) throws SecurityException
Set the accessible flag for this object to the indicated boolean value. A value of true indicates that the reflected object should suppress Java language access checking when it is used. A value of false indicates that the reflected object should enforce Java language access checks.
<!-- Generated by javadoc (build 1.6.0) on Wed Nov 29 02:21:29 PST 2006 -->
调用setAccessible方法并设置参数值为true时,便可以实现对当前成员的访问检测的压制,即是说调用Field,Method,Constructor的setAccessibleObject(true)时会使字段,方法,和构造方法的控制检测失效,以达到我们上面修改另一个类的私有成员的目的。
参加下面的代码:
public class PrivateTest {
private String str;
public PrivateTest(String str) {
this.str = str;
}
public String getStr() {
return str;
}
}
public class ReflectionTest {
public static void main(String[] args) throws Exception {
PrivateTest pt = new PrivateTest("hello");
//得到PrivateTest的Class对象,通过调用对象的getClass()或者直接从类得到
// Class classType = pt.getClass();
Class classType = PrivateTest.class;
//得到相应class中指定名称字段的Field对象
Field field = classType.getDeclaredField("str");
// Field field = classType.getField("str"); 使用此方法不能得到private修饰符修饰的成员
//设置该字段的setAccessible方法值为true,即压制访问检测
field.setAccessible(true);
//直接通过Field的get方法获得参数对应的对象的字段值
String str = (String) field.get(pt);
System.out.println(str);
//压制访问检测后,通过Field的set方法为类的似有字段设置值
field.set(pt, "world");
System.out.println(pt.getStr());
}
}