文档

Java™ 教程-Java Tutorials 中文版
获取和设置数组及其组件
Trail: The Reflection API
Lesson: Arrays and Enumerated Types
Section: Arrays

获取和设置数组及其组件

正如在非反射代码中一样,可以整体地或逐个组件地设置或获取数组字段。要一次设置整个数组,请使用 java.lang.reflect.Field.set(Object obj, Object value)。要获取整个数组,请使用 Field.get(Object)。可以使用 java.lang.reflect.Array 中的方法设置或获取单个组件。

Array提供 setFoo()getFoo() 用于设置和获取任何基本类型的组件。例如,int 数组的组件可以使用 Array.setInt(Object array, int index, int value) 进行设置,并且使用 Array.getInt(Object array, int index) 获取。

这些方法支持自动 widening (扩展) 数据类型。因此,Array.getShort() 可用于设置 int 数组的值,因为 16 位 short 可以扩展到 32 位 int 而不会丢失数据;另一方面,在 int 数组上调用 Array.setLong() 会导致 IllegalArgumentException 因为 64 位 long 无法缩小到存储在 32 位 int 中而不丢失信息。无论传递的实际值是否可以在目标数据类型中准确表示,都是如此。The Java Language Specification, Java SE 7 EditionWidening Primitive ConversionNarrowing Primitive Conversion 部分包含完整的讨论扩大和缩小转换。

使用 Array.set(Object array, int index, int value)Array.get(Object array, int index) 设置和获取引用类型数组(包括数组的数组)的组件。

设置数组类型的字段

GrowBufferedReader 示例说明了如何替换数组类型字段的值。在这种情况下,代码用较大的数组替换 java.io.BufferedReader 的后备数组。(这假设原始 BufferedReader 的创建是在不可修改的代码中;否则,简单地使用备用构造函数 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

请注意,上面的示例使用了数组实用程序方法 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) 提供了一种创建多维数组的便捷方法,但组件仍然需要使用多维数组是嵌套数组的原则初始化。(为此,反射不提供多个索引的 get/set 方法。)


Previous page: Creating New Arrays
Next page: Troubleshooting