Troubleshooting

以下示例显示了对阵列进行操作时可能发生的典型错误。

IllegalArgumentException 由于类型不可转换

ArrayTroubleAgain示例将生成IllegalArgumentException。调用Array.setInt()来设置参考类型为Integer的组件,其值的原始类型为int。在非反射等效项ary[0] = 1中,编译器会将值1转换(或* box *)为参考类型new Integer(1),以便其类型检查将接受该语句。使用反射时,类型检查仅在运行时发生,因此没有机会将值装箱。

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

为了消除此异常,应将以下行Array.set(对象数组,整数索引,对象值)替换为有问题的行:

Array.set(ary, 0, new Integer(1));

Tip:

使用反射设置或获取数组组件时,编译器没有机会执行装箱。它只能转换与Class.isAssignableFrom()规范中所述相关的类型。该示例预计会失败,因为isAssignableFrom()在此测试中将返回false,可以通过编程将其用于验证特定转换是否可行:

Integer.class.isAssignableFrom(int.class) == false

同样,从原始类型到引用类型的自动转换也无法反映出来。

int.class.isAssignableFrom(Integer.class) == false

空数组的 ArrayIndexOutOfBoundsException

ArrayTrouble示例说明了如果try访问零 Long 度数组的元素将发生的错误:

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)

Tip:

可能有没有元素的数组(空数组)。在普通代码中只有少数情况可以看到它们,但是它们可能会在无意中反射发生。当然,不可能设置/获取空数组的值,因为将抛出ArrayIndexOutOfBoundsException

IllegalArgumentException 如果try缩小

ArrayTroubleToo示例包含失败的代码,因为它try执行可能会丢失数据的操作:

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)

Tip:

Array.set*()Array.get*()方法将执行自动加宽转换,但是如果try进行缩小转换将抛出IllegalArgumentException。有关扩大和缩小转换的完整讨论,请分别参见Java 语言规范,Java SE 7 版扩大原始转换缩小原始转换部分。