在字节码级别,Java 的 Class.getEnumConstants() 如何知道哪些类是枚举类?



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()方法。

相关内容

  • 没有找到相关文章

最新更新