文档

Java™教程
隐藏目录
故障排除
路径: 反射API
课程: 数组和枚举类型
章节: 数组

故障排除

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

由于不可转换类型而引发的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("无法装箱%n");
	} catch (ArrayIndexOutOfBoundsException x) {
	    x.printStackTrace();
	}
    }
}
$ java ArrayTroubleAgain
无法装箱

要消除此异常,应将问题行替换为以下调用: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);  // 扩大转换,成功
        Array.setLong(o, 1, 2L);         // 缩小转换,失败
    }
}
$ 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 Edition扩大的基本类型转换缩小的基本类型转换章节。

上一页: 获取和设置数组及其组件
下一页: 枚举类型