获取和设置数组及其组件

就像在非反射代码中一样,可以整个或逐个组件设置或检索数组字段。要一次设置整个阵列,请使用java.lang.reflect.Field.set(Object obj,Object value)。要检索整个数组,请使用Field.get(Object)。可以使用java.lang.reflect.Array中的方法来设置或检索各个组件。

Array提供了setFoo()getFoo()形式的方法,用于设置和获取任何原始类型的组件。例如,int数组的成分可以设置为Array.setInt(对象数组,整数索引,整数值),也可以使用Array.getInt(对象数组,int 索引)检索。

这些方法支持自动扩展数据类型。因此,Array.getShort()可以用于设置int数组的值,因为 16 位short可以扩展为 32 位int而不会丢失数据。另一方面,在int数组上调用Array.setLong()将引发IllegalArgumentException,因为不能将 64 位long缩小到 32 位int的大小而不会丢失信息。不管传递的实际值是否可以在目标数据类型中准确表示,这都是正确的。 Java 语言规范,Java SE 7 版扩大原始转换缩小原始转换部分包含有关扩大和缩小转换的完整讨论。

使用Array.set(对象数组,整数索引,整数值)Array.get(对象数组,整数索引)设置和检索引用类型的数组的组成部分(包括数组的数组)。

设置类型数组的字段

GrowBufferedReader示例说明了如何替换类型为 array 的字段的值。在这种情况下,代码将java.io.BufferedReader的后备数组替换为较大的java.io.BufferedReader。 (这假设原始BufferedReader的创建是在不可修改的代码中进行的;否则,简单地使用接受 Importing 缓冲区大小的备用构造函数BufferedReader(java.io.Reader in,int size)将是微不足道的。)

import java.io.BufferedReader;
import java.io.CharArrayReader;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.lang.reflect.Field;
import java.util.Arrays;
import static java.lang.System.out;

public class GrowBufferedReader {
    private static final int srcBufSize = 10 * 1024;
    private static char[] src = new char[srcBufSize];
    static {
	src[srcBufSize - 1] = 'x';
    }
    private static CharArrayReader car = new CharArrayReader(src);

    public static void main(String... args) {
	try {
	    BufferedReader br = new BufferedReader(car);

	    Class<?> c = br.getClass();
	    Field f = c.getDeclaredField("cb");

	    // cb is a private field
	    f.setAccessible(true);
	    char[] cbVal = char[].class.cast(f.get(br));

	    char[] newVal = Arrays.copyOf(cbVal, cbVal.length * 2);
	    if (args.length > 0 && args[0].equals("grow"))
		f.set(br, newVal);

	    for (int i = 0; i < srcBufSize; i++)
		br.read();

	    // see if the new backing array is being used
	    if (newVal[srcBufSize - 1] == src[srcBufSize - 1])
		out.format("Using new backing array, size=%d%n", newVal.length);
	    else
		out.format("Using original backing array, size=%d%n", cbVal.length);

        // production code should handle these exceptions more gracefully
	} catch (FileNotFoundException x) {
	    x.printStackTrace();
	} catch (NoSuchFieldException x) {
	    x.printStackTrace();
	} catch (IllegalAccessException x) {
	    x.printStackTrace();
	} catch (IOException x) {
	    x.printStackTrace();
	}
    }
}
$ java GrowBufferedReader grow
Using new backing array, size=16384
$ java GrowBufferedReader
Using original backing array, size=8192

请注意,上面的示例使用了数组 Util 方法java.util.Arrays.copyOf)java.util.Arrays包含许多对数组进行操作时很方便的方法。

访问多维数组的元素

多维数组只是嵌套数组。二维数组是数组的数组。三维数组是二维数组的数组,依此类推。 CreateMatrix示例说明了如何使用反射创建和初始化多维数组。

import java.lang.reflect.Array;
import static java.lang.System.out;

public class CreateMatrix {
    public static void main(String... args) {
        Object matrix = Array.newInstance(int.class, 2, 2);
        Object row0 = Array.get(matrix, 0);
        Object row1 = Array.get(matrix, 1);

        Array.setInt(row0, 0, 1);
        Array.setInt(row0, 1, 2);
        Array.setInt(row1, 0, 3);
        Array.setInt(row1, 1, 4);

        for (int i = 0; i < 2; i++)
            for (int j = 0; j < 2; j++)
                out.format("matrix[%d][%d] = %d%n", i, j, ((int[][])matrix)[i][j]);
    }
}
$ java CreateMatrix
matrix[0][0] = 1
matrix[0][1] = 2
matrix[1][0] = 3
matrix[1][1] = 4

通过使用以下代码片段,可以获得相同的结果:

Object matrix = Array.newInstance(int.class, 2);
Object row0 = Array.newInstance(int.class, 2);
Object row1 = Array.newInstance(int.class, 2);

Array.setInt(row0, 0, 1);
Array.setInt(row0, 1, 2);
Array.setInt(row1, 0, 3);
Array.setInt(row1, 1, 4);

Array.set(matrix, 0, row0);
Array.set(matrix, 1, row1);

变量参数Array.newInstance(Class<?> componentType,int ... Dimensions)提供了一种创建多维数组的便捷方法,但是仍然需要使用多维数组是嵌套数组的原理来初始化组件。 (为此,Reflection 不提供多个索引的get/set方法.)