文档

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

故障排除

以下示例显示使用枚举类型可能遇到的问题。

在实例化枚举类型时抛出IllegalArgumentException

如前所述,枚举类型的实例化是禁止的。 EnumTrouble 示例试图进行此操作。

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import static java.lang.System.out;

enum Charge {
    POSITIVE, NEGATIVE, NEUTRAL;
    Charge() {
	out.format("正在构建中%n");
    }
}

public class EnumTrouble {

    public static void main(String... args) {
	try {
	    Class<?> c = Charge.class;

 	    Constructor[] ctors = c.getDeclaredConstructors();
 	    for (Constructor ctor : ctors) {
		out.format("构造函数:%s%n",  ctor.toGenericString());
 		ctor.setAccessible(true);
 		ctor.newInstance();
 	    }

        // 产品代码应更优雅地处理这些异常
	} catch (InstantiationException x) {
	    x.printStackTrace();
	} catch (IllegalAccessException x) {
	    x.printStackTrace();
	} catch (InvocationTargetException x) {
	    x.printStackTrace();
	}
    }
}
$ java EnumTrouble
构造函数:private Charge()
Exception in thread "main" java.lang.IllegalArgumentException: 无法通过反射创建枚举对象
        at java.lang.reflect.Constructor.newInstance(Constructor.java:511)
        at EnumTrouble.main(EnumTrouble.java:22)

提示: 尝试显式实例化枚举是一个编译时错误,因为这将阻止定义的枚举常量的唯一性。此限制在反射代码中也得到执行。试图使用默认构造函数实例化类的代码应该先调用Class.isEnum()来确定该类是否是一个枚举。

在使用不兼容的枚举类型设置字段时抛出IllegalArgumentException

存储枚举的字段必须使用相应的枚举类型进行设置。实际上,任何类型的字段都必须使用兼容的类型进行设置。 EnumTroubleToo 示例产生了预期的错误。

import java.lang.reflect.Field;

enum E0 { A, B }
enum E1 { A, B }

class ETest {
    private E0 fld = E0.A;
}

public class EnumTroubleToo {
    public static void main(String... args) {
	try {
	    ETest test = new ETest();
	    Field f = test.getClass().getDeclaredField("fld");
	    f.setAccessible(true);
 	    f.set(test, E1.A);  // IllegalArgumentException

        // 产品代码应更优雅地处理这些异常
	} catch (NoSuchFieldException x) {
	    x.printStackTrace();
	} catch (IllegalAccessException x) {
	    x.printStackTrace();
	}
    }
}
$ java EnumTroubleToo
在主线程中发生异常:java.lang.IllegalArgumentException: 无法将 E0 字段设置为 E1
        at sun.reflect.UnsafeFieldAccessorImpl.throwSetIllegalArgumentException
          (UnsafeFieldAccessorImpl.java:146)
        at sun.reflect.UnsafeFieldAccessorImpl.throwSetIllegalArgumentException
          (UnsafeFieldAccessorImpl.java:150)
        at sun.reflect.UnsafeObjectFieldAccessorImpl.set
          (UnsafeObjectFieldAccessorImpl.java:63)
        at java.lang.reflect.Field.set(Field.java:657)
        at EnumTroubleToo.main(EnumTroubleToo.java:16)

提示: 严格来说,只有当以下条件成立时,才能将类型为 X 的字段设置为类型为 Y 的值:
X.class.isAssignableFrom(Y.class) == true
可以修改代码执行以下测试,以验证类型是否兼容:
if (f.getType().isAssignableFrom(E0.class))
    // 兼容
else
    // 期望抛出 IllegalArgumentException


上一页: 通过枚举类型获取和设置字段
下一页: 结束