Java反射类java.lang.reflect.Array类介绍

x33g5p2x  于2021-08-20 转载在 Java  
字(5.8k)|赞(0)|评价(0)|浏览(353)

1. 概述

Array有一个组件类型和一个长度(不属于该类型的一部分)。Array可以被整体操作,也可以被逐个组件操作。反射提供了java.lang.reflect.Array类。本帖的源代码可以在GitHub上找到。
下面的类图显示了Array类提供的所有反射API。

2. 用于Arrays的Java反射

  • 识别Array类型 - 描述了如何确定一个类成员是否是Array类型的字段
  • 创建新的Arrays - 说明如何用简单和复杂的组件类型创建Arrays的新实例
  • 获取和设置Arrays及其组件 - 说明如何访问Array类型的字段和单独访问Array元素

2.1 识别Array类型

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

2.2 创建新的Arrays

反射支持通过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]

2.3 获取和设置Array及其组件

  1. 一个Array字段可以整体设置或检索,也可以逐个组件设置或检索。
  2. 要一次性设置整个Array,请使用java.lang.reflect.Field.set(Object obj, Object value)。
  3. 要检索整个Array,使用Field.get(Object)。
  4. 可以使用java.lang.reflect.Array中的方法来设置或检索单个组件。

设置一个Array类型的字段

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

访问多维Array的元素

多维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

3. 参考资料

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

相关文章