获取和设置数组及其组件

原文: https://docs.oracle.com/javase/tutorial/reflect/special/arraySetGet.html

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

Array 提供设置 _Foo_ ()获取 _Foo_ ()形式的方法进行设置和获取任何基本类型的组件。例如,int阵列的组分可以用 Array.setInt(Object array, int index, int value) 设置,并且可以用 Array.getInt(Object array, int index) 检索。

这些方法支持数据类型的自动扩展。因此, Array.getShort() 可用于设置int阵列的值,因为 16 位short可以加宽到 32 位int而不会丢失数据;另一方面,在int数组上调用 Array.setLong() 将导致 IllegalArgumentException 被抛出,因为 64 位long无法缩小到存储在 32 位int中而不会丢失信息。无论传递的实际值是否可以在目标数据类型中准确表示,都是如此。 Java 语言规范,Java SE 7 版 拓宽原始转换缩小原始转换包含对扩展和缩小的完整讨论转换。

使用 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) 将是微不足道的。)

  1. import java.io.BufferedReader;
  2. import java.io.CharArrayReader;
  3. import java.io.FileNotFoundException;
  4. import java.io.IOException;
  5. import java.lang.reflect.Field;
  6. import java.util.Arrays;
  7. import static java.lang.System.out;
  8. public class GrowBufferedReader {
  9. private static final int srcBufSize = 10 * 1024;
  10. private static char[] src = new char[srcBufSize];
  11. static {
  12. src[srcBufSize - 1] = 'x';
  13. }
  14. private static CharArrayReader car = new CharArrayReader(src);
  15. public static void main(String... args) {
  16. try {
  17. BufferedReader br = new BufferedReader(car);
  18. Class<?> c = br.getClass();
  19. Field f = c.getDeclaredField("cb");
  20. // cb is a private field
  21. f.setAccessible(true);
  22. char[] cbVal = char[].class.cast(f.get(br));
  23. char[] newVal = Arrays.copyOf(cbVal, cbVal.length * 2);
  24. if (args.length > 0 && args[0].equals("grow"))
  25. f.set(br, newVal);
  26. for (int i = 0; i < srcBufSize; i++)
  27. br.read();
  28. // see if the new backing array is being used
  29. if (newVal[srcBufSize - 1] == src[srcBufSize - 1])
  30. out.format("Using new backing array, size=%d%n", newVal.length);
  31. else
  32. out.format("Using original backing array, size=%d%n", cbVal.length);
  33. // production code should handle these exceptions more gracefully
  34. } catch (FileNotFoundException x) {
  35. x.printStackTrace();
  36. } catch (NoSuchFieldException x) {
  37. x.printStackTrace();
  38. } catch (IllegalAccessException x) {
  39. x.printStackTrace();
  40. } catch (IOException x) {
  41. x.printStackTrace();
  42. }
  43. }
  44. }
  1. $ java GrowBufferedReader grow
  2. Using new backing array, size=16384
  3. $ java GrowBufferedReader
  4. Using original backing array, size=8192

请注意,上面的示例使用了数组实用程序方法 java.util.Arrays.copyOf)java.util.Arrays 包含许多在阵列上操作时很方便的方法。

访问多维数组的元素

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

  1. import java.lang.reflect.Array;
  2. import static java.lang.System.out;
  3. public class CreateMatrix {
  4. public static void main(String... args) {
  5. Object matrix = Array.newInstance(int.class, 2, 2);
  6. Object row0 = Array.get(matrix, 0);
  7. Object row1 = Array.get(matrix, 1);
  8. Array.setInt(row0, 0, 1);
  9. Array.setInt(row0, 1, 2);
  10. Array.setInt(row1, 0, 3);
  11. Array.setInt(row1, 1, 4);
  12. for (int i = 0; i < 2; i++)
  13. for (int j = 0; j < 2; j++)
  14. out.format("matrix[%d][%d] = %d%n", i, j, ((int[][])matrix)[i][j]);
  15. }
  16. }
  1. $ java CreateMatrix
  2. matrix[0][0] = 1
  3. matrix[0][1] = 2
  4. matrix[1][0] = 3
  5. matrix[1][1] = 4

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

  1. Object matrix = Array.newInstance(int.class, 2);
  2. Object row0 = Array.newInstance(int.class, 2);
  3. Object row1 = Array.newInstance(int.class, 2);
  4. Array.setInt(row0, 0, 1);
  5. Array.setInt(row0, 1, 2);
  6. Array.setInt(row1, 0, 3);
  7. Array.setInt(row1, 1, 4);
  8. Array.set(matrix, 0, row0);
  9. Array.set(matrix, 1, row1);

变量参数 Array.newInstance(Class&lt;?&gt; componentType, int... dimensions) 提供了一种创建多维数组的便捷方法,但仍需要使用多维数组是嵌套数组的原则来初始化组件。 (反射不为此目的提供多索引get / set方法。)