确定数组类型
可以通过方法 Class.isArray() 来确定一个类型是否是数组类型:
- import java.lang.reflect.Field;
- import java.lang.reflect.Type;
- import static java.lang.System.out;
- public class ArrayFind {public static void main(String... args) {
- boolean found = false;
- try {
- Class<?> cls = Class.forName(args[0]);
- Field[] flds = cls.getDeclaredFields();
- for (Field f : flds) {
- Class<?> c = f.getType();
- if (c.isArray()) {
- found = true;
- out.format("%s%n"
- + "Field: %s%n"
- + "Type: %s%n"
- + "Component Type: %s%n",
- f, f.getName(), c, c.getComponentType());
- }
- }
- if (!found) {
- out.format("No array fields%n");
- }
- // production code should handle this exception more gracefully
- } catch (ClassNotFoundException x) {
- x.printStackTrace();
- }
- }
- }
运行结果:
- $java ArrayFind java.nio.ByteBuffer
- final byte[] java.nio.ByteBuffer.hb
- Field: hb
- Type: class [B
- Component Type: byte
- $ java ArrayFind java.lang.Throwable
- private java.lang.StackTraceElement[] java.lang.Throwable.stackTrace
- Field: stackTrace
- Type: class [Ljava.lang.StackTraceElement;
- Component Type: class java.lang.StackTraceElement
- $ java ArrayFind java.awt.Cursor
- protected static java.awt.Cursor[] java.awt.Cursor.predefined
- Field: predefined
- Type: class [Ljava.awt.Cursor;
- Component Type: class java.awt.Cursor
- static final java.lang.String[][] java.awt.Cursor.cursorProperties
- Field: cursorProperties
- Type: class [[Ljava.lang.String;
- Component Type: class [Ljava.lang.String;
'['的个数表示的数组的维度, getComponentType() 获取的是其组成元素的类型.
创建数组
通过 java.lang.reflect.Array.newInstance() 可以创建动态创建数组.
- import java.lang.reflect.Array;
- import java.lang.reflect.Constructor;
- import java.lang.reflect.InvocationTargetException;
- import java.util.regex.Pattern;
- import java.util.regex.Matcher;
- import java.util.Arrays;
- import static java.lang.System.out;
- public class ArrayCreator {
- private static String s = "java.math.BigInteger bi[] = { 123, 234, 345 }";
- private static Pattern p = Pattern.compile("^\\s*(\\S+)\\s*\\w+\\[\\].*\\{\\s*([^}]+)\\s*\\}");
- public static void main(String... args) {
- Matcher m = p.matcher(s);
- if (m.find()) {
- String cName = m.group(1);
- String[] cVals = m.group(2).split("[\\s,]+");
- int n = cVals.length;
- try {
- Class<?> c = Class.forName(cName);
- Object o = Array.newInstance(c, n);
- for (int i = 0; i <n; i++) {
- String v = cVals[i];
- Constructor ctor = c.getConstructor(String.class);
- Object val = ctor.newInstance(v);
- Array.set(o, i, val);
- }
- Object[] oo = (Object[])o;
- out.format("%s[] = %s%n", cName, Arrays.toString(oo));
- // production code should handle these exceptions more gracefully
- } catch (ClassNotFoundException x) {
- x.printStackTrace();
- } catch (NoSuchMethodException x) {
- x.printStackTrace();
- } catch (IllegalAccessException x) {
- x.printStackTrace();
- } catch (InstantiationException x) {
- x.printStackTrace();
- } catch (InvocationTargetException x) {
- x.printStackTrace();
- }
- }
- }
- }
运行结果:
- $ java ArrayCreator
- java.math.BigInteger [] = [123, 234, 345]
获取, 设置数组和其元素
可以通过 java.lang.reflect.Array 中的发 setXxx(),getXxx() 来设置和获取任何原生类型元素, 例如, Array.setInt(Object array, int index, int value),Array.getInt(Object object, int index). 而且这些方法支持数据类型的自动扩展, 例如可以调用 Array.setShort() 将 short 类型的只设置到 int 的数组中, 但是不能调用 Array.setLong() 将 long 类型设置到 int 的数组中, 会抛出 IllegalArgumentException. 下面的例子是将 java.io.BufferedReader 的内部 char[] 替换为一个更大的数组:
- 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
设置获取多维数组
示例:
- 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);
问题排查
无法进行类型转换和缩小类型范围导致 IllegalArgumentException
例如:
- import java.lang.reflect.Array;
- import static java.lang.System.err;
- public class ArrayTroubleAgain {
- public static void main(String... args) {
- Integer[] ary = new Integer[2];
- try {
- Array.setInt(ary, 0, 1); // IllegalArgumentException
- // production code should handle these exceptions more gracefully
- } catch (IllegalArgumentException x) {
- err.format("Unable to box%n");
- } catch (ArrayIndexOutOfBoundsException x) {
- x.printStackTrace();
- }
- }
- }
运行
- $ java ArrayTroubleAgain
- Unable to box
- import java.lang.reflect.Array;
- import static java.lang.System.out;
- public class ArrayTroubleToo {
- public static void main(String... args) {
- Object o = new int[2];
- Array.setShort(o, 0, (short)2); // widening, succeeds
- Array.setLong(o, 1, 2L); // narrowing, fails
- }
- }
运行:
- $ java ArrayTroubleToo
- Exception in thread "main" java.lang.IllegalArgumentException: argument type
- mismatch
- at java.lang.reflect.Array.setLong(Native Method)
- at ArrayTroubleToo.main(ArrayTroubleToo.java:9)
抛出 ArrayIndexOutOfBoundsException
- import java.lang.reflect.Array;
- import static java.lang.System.out;
- public class ArrayTrouble {
- public static void main(String... args) {
- Object o = Array.newInstance(int.class, 0);
- int[] i = (int[])o;
- int[] j = new int[0];
- out.format("i.length = %d, j.length = %d, args.length = %d%n",
- i.length, j.length, args.length);
- Array.getInt(o, 0); // ArrayIndexOutOfBoundsException
- }
- }
运行结果:
- $ java ArrayTrouble
- i.length = 0, j.length = 0, args.length = 0
- Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException
- at java.lang.reflect.Array.getInt(Native Method)
- at ArrayTrouble.main(ArrayTrouble.java:11)
来源: https://juejin.im/entry/5ae5c0c2518825673278000a