前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >反射基础之Array

反射基础之Array

作者头像
代码拾遗
发布2018-07-24 15:50:34
5000
发布2018-07-24 15:50:34
举报
文章被收录于专栏:代码拾遗代码拾遗
确定数组类型

可以通过方法Class.isArray()来确定一个类型是否是数组类型:

代码语言:javascript
复制
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();
    }
    }
}

运行结果:

代码语言:javascript
复制
$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()可以创建动态创建数组。

代码语言:javascript
复制
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();
            }
        }
    }
}

运行结果:

代码语言:javascript
复制
$ 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[]替换为一个更大的数组:

代码语言:javascript
复制
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();
    }
    }
}

运行结果:

代码语言:javascript
复制
$ java GrowBufferedReader grow
Using new backing array, size=16384
$ java GrowBufferedReader
Using original backing array, size=8192
设置获取多维数组

示例:

代码语言:javascript
复制
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]);
    }
}

运行:

代码语言:javascript
复制
$ java CreateMatrix
matrix[0][0] = 1
matrix[0][1] = 2
matrix[1][0] = 3
matrix[1][1] = 4

下面代码实现了相同的功能:

代码语言:javascript
复制
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

例如:

代码语言:javascript
复制
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();
    }
    }
}

运行

代码语言:javascript
复制
$ java ArrayTroubleAgain
Unable to box
代码语言:javascript
复制
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
    }
}

运行:

代码语言:javascript
复制
$ 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
代码语言:javascript
复制
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
    }
}

运行结果:

代码语言:javascript
复制
$ 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)
本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2018-05-11,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 代码拾遗 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 确定数组类型
  • 创建数组
  • 获取,设置数组和其元素
    • 设置获取多维数组
    • 问题排查
      • 无法进行类型转换和缩小类型范围导致 IllegalArgumentException
        • 抛出 ArrayIndexOutOfBoundsException
        领券
        问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档