Java 反射 API 包含一个方法Class.getEnumConstants()
,可以确定类是否是enum
类(如果它不认为类是enum
,则返回null
),以及它的常量是什么。
我正在开发一个直接生成 JVM 字节码的程序,并正在尝试生成一个枚举类。因此,我需要知道 Java 如何从字节码中识别枚举类,以便getEnumConstants
正常工作。显然,该类需要扩展Enum
,但这本身显然是不够的(例如,对应于public class Example extends Enum<Example> {}
的字节码不会被识别为enum
);一个类的JVM字节码还需要具有哪些其他功能,以便Java的反射API将其识别为Javaenum
,并能够确定其枚举常量?
为了编译enum
类型,您必须在类的访问标志中使用ACC_ENUM
标志标记该类。
此外,对于每个常量,您必须创建一个相应的public static final
字段,该字段也在字段的访问标志中标有ACC_ENUM
。
然后,您需要一个类初始值设定项(一个名为<clinit>
的 no-argvoid
方法),用于创建实例并将它们分配给字段。
但这还不够。注意语言规范,它指定了两个隐式声明方法的存在
/** * Returns an array containing the constants of this enum * type, in the order they're declared. This method may be * used to iterate over the constants as follows: * * for(E c : E.values()) * System.out.println(c); * * @return an array containing the constants of this enum * type, in the order they're declared */ public static E[] values(); /** * Returns the enum constant of this type with the specified * name. * The string must match exactly an identifier used to declare * an enum constant in this type. (Extraneous whitespace * characters are not permitted.) * * @return the enum constant with the specified name * @throws IllegalArgumentException if this enum type has no * constant with the specified name */ public static E valueOf(String name);
编译器或字节码生成工具的职责是将其实现插入到特定的枚举类型。请注意,尽管是编译器生成的,但这两个方法不应标记为合成方法。
规范没有解决反射将如何收集其信息的问题。它可以遍历标记的字段并读取它们,以组装数组,或者它可以只调用特定类型的values()
方法。因此,您不能省略这些工件中的任何一个,也不能通过仅委托给Class.getEnumConstants()
来实现values()
方法。