Array有一个组件类型和一个长度(不属于该类型的一部分)。Array可以被整体操作,也可以被逐个组件操作。反射提供了java.lang.reflect.Array类。本帖的源代码可以在GitHub上找到。
下面的类图显示了Array类提供的所有反射API。
Array类型可以通过调用Class.isArray()来识别。
在ArrayFind的例子中,可以识别命名的类中属于Array类型的字段,并报告每个字段的组件类型。
package com.javaguides.reflection.arrays;
import static java.lang.System.out;
import java.lang.reflect.Field;
public class ArrayFind {
public static void main(String... args) {
boolean found = false;
try {
Class<?> cls = Class.forName("java.nio.ByteBuffer");
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();
}
}
}
输出。
final byte[] java.nio.ByteBuffer.hb
Field: hb
Type: class [B
Component Type: byte
让我们把java.lang.Throwable参数传给Class.forName("java.lang.Throwable")方法。一个Array的引用类型StackTraceElement 输出。
private static final java.lang.StackTraceElement[] java.lang.Throwable.UNASSIGNED_STACK
Field: UNASSIGNED_STACK
Type: class [Ljava.lang.StackTraceElement;
Component Type: class java.lang.StackTraceElement
private java.lang.StackTraceElement[] java.lang.Throwable.stackTrace
Field: stackTrace
Type: class [Ljava.lang.StackTraceElement;
Component Type: class java.lang.StackTraceElement
private static final java.lang.Throwable[] java.lang.Throwable.EMPTY_THROWABLE_ARRAY
Field: EMPTY_THROWABLE_ARRAY
Type: class [Ljava.lang.Throwable;
Component Type: class java.lang.Throwable
反射支持通过java.lang.reflect.Array.newInstance()动态地创建任意类型和尺寸的Arrays的能力。
让我们写一个例子来通过反射创建一个Array。
package com.javaguides.reflection.arrays;
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.math.BigInteger[] = [123, 234, 345]
GrowBufferedReader的例子说明了如何替换一个Array类型的字段的值。在这种情况下,代码将一个java.io.BufferedReader的后备Array替换成一个更大的。(这假定原始BufferedReader的创建是在不可修改的代码中进行的;否则,简单地使用替代的构造函数BufferedReader(java.io.Reader in, int size),接受一个输入缓冲区的大小就很简单了。)
package com.javaguides.reflection.arrays;
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 ("grow".length() > 0 && "grow".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();
}
}
}
输出:
Using new backing array, size=16384
多维Arrays是简单的嵌套Arrays。一个二维Array是Array的Array。三维Array是二维Array的Array,以此类推。
CreateMatrix例子说明了如何使用反射创建和初始化一个多维Array。
package com.javaguides.reflection.arrays;
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]);
}
}
输出。
matrix[0][0] = 1
matrix[0][1] = 2
matrix[1][0] = 3
matrix[1][1] = 4
https://docs.oracle.com/javase/tutorial/reflect/class/index.html
https://docs.oracle.com/javase/8/docs/api/java/lang/reflect/package-summary.html
https://docs.oracle.com/javase/8/docs/api/java/lang/reflect/Array.html
版权说明 : 本文为转载文章, 版权归原作者所有 版权申明
原文链接 : https://www.javaguides.net/2018/07/java-reflection-for-arrays.html
内容来源于网络,如有侵权,请联系作者删除!