文档

Java™ 教程-Java Tutorials 中文版
故障排除
Trail: The Reflection API
Lesson: Arrays and Enumerated Types
Section: Arrays

故障排除

以下示例显示了在数组上操作时可能出现的典型错误。

由于不可转换类型导致的 IllegalArgumentException

ArrayTroubleAgain 示例将生成 IllegalArgumentException。调用 Array.setInt() 以设置引用类型 Integer 的组件,其值为基本类型 int。在非反射等价物 ary[0] = 1 中,编译器会将值转换(装箱)为引用类型 1 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(Object array, int index, Object value)

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

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

类似地,在反射中也不可能从基本类型到引用类型的自动转换。

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

空数组的 ArrayIndexOutOfBoundsException

ArrayTrouble 示例说明了在尝试访问零长度数组的元素时将发生的错误:


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)

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

尝试缩小时发生 IllegalArgumentException

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


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)

提示: Array.set*()Array.get*() 方法将执行自动扩大转换,但如果尝试缩小转换会抛出 IllegalArgumentException。有关扩大和缩小转换的完整讨论,请分别参阅 The Java Language Specification, Java SE 7 EditionWidening Primitive ConversionNarrowing Primitive Conversion 部分。

Previous page: Getting and Setting Arrays and Their Components
Next page: Enumerated Types