# 故障排除

> 原文： [https://docs.oracle.com/javase/tutorial/reflect/special/enumTrouble.html](https://docs.oracle.com/javase/tutorial/reflect/special/enumTrouble.html)

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

## 尝试实例化枚举类型时出现 IllegalArgumentException

如前所述，禁止实例化枚举类型。 [``EnumTrouble`` ](example/EnumTrouble.java)的例子试图这样做。

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

enum Charge {
    POSITIVE, NEGATIVE, NEUTRAL;
    Charge() {
	out.format("under construction%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("Constructor: %s%n",  ctor.toGenericString());
 		ctor.setAccessible(true);
 		ctor.newInstance();
 	    }

        // production code should handle these exceptions more gracefully
	} catch (InstantiationException x) {
	    x.printStackTrace();
	} catch (IllegalAccessException x) {
	    x.printStackTrace();
	} catch (InvocationTargetException x) {
	    x.printStackTrace();
	}
    }
}

```

```
$ java EnumTrouble
Constructor: private Charge()
Exception in thread "main" java.lang.IllegalArgumentException: Cannot
  reflectively create enum objects
        at java.lang.reflect.Constructor.newInstance(Constructor.java:511)
        at EnumTrouble.main(EnumTrouble.java:22)

```

* * *

**Tip:** It is a compile-time error to attempt to explicitly instantiate an enum because that would prevent the defined enum constants from being unique. This restriction is also enforced in reflective code. Code which attempts to instantiate classes using their default constructors should invoke [`Class.isEnum()`](https://docs.oracle.com/javase/8/docs/api/java/lang/Class.html#isEnum--) first to determine if the class is an enum.

* * *

## 设置具有不兼容枚举类型的字段时出现 IllegalArgumentException

存储枚举的字段使用适当的枚举类型设置。 （实际上，_ 任何 _ 类型的字段必须设置为兼容类型。） [``EnumTroubleToo``](example/EnumTroubleToo.java)示例产生预期错误。

```
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

        // production code should handle these exceptions more gracefully
	} catch (NoSuchFieldException x) {
	    x.printStackTrace();
	} catch (IllegalAccessException x) {
	    x.printStackTrace();
	}
    }
}

```

```
$ java EnumTroubleToo
Exception in thread "main" java.lang.IllegalArgumentException: Can not set E0
  field ETest.fld to 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)

```

* * *

**Tip:** Strictly speaking, any attempt to set a field of type `X` to a value of type `Y` can only succeed if the following statement holds:

```
X.class.isAssignableFrom(Y.class) == true

```

The code could be modified to perform the following test to verify whether the types are compatible:

```
if (f.getType().isAssignableFrom(E0.class))
    // compatible
else
    // expect IllegalArgumentException

```

* * *