Java 教程是为 JDK 8 编写的。本页中描述的示例和实践未利用在后续版本中引入的改进。
正如在非反射代码中一样,可以整体地或逐个组件地设置或获取数组字段。要一次设置整个数组,请使用 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 Edition,Widening Primitive Conversion 和 Narrowing Primitive Conversion 部分包含完整的讨论扩大和缩小转换。
使用 Array.set(Object array, int index, int value) 和 Array.get(Object array, int index) 设置和获取引用类型数组(包括数组的数组)的组件。
示例说明了如何替换数组类型字段的值。在这种情况下,代码用较大的数组替换 GrowBufferedReaderjava.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 方法。)