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

smi*_*aiw 2 java reflection enums jvm-bytecode

Java 反射 API 包含一个方法Class.getEnumConstants(),可以确定一个类是否是一个enum类(null如果它认为该类不是一个enum,则返回),以及它的常量是什么。

我正在开发一个直接生成 JVM 字节码的程序,并试图生成一个枚举类。因此,我需要知道 Java 如何从字节码中识别枚举类,这样getEnumConstants才能正常工作。显然,该类需要扩展Enum,但这显然是不够的(例如,对应于 的字节码public class Example extends Enum<Example> {}不会被识别为enum);类的 JVM 字节码还需要哪些其他功能,以便 Java 的反射 API 将其识别为 Java enum,并能够确定其枚举常量?

Hol*_*ger 5

为了编译一个enum类型,你必须用ACC_ENUM类的访问标志中的标志来标记该类。

此外,对于每个常量,您必须创建一个相应的public static final字段,ACC_ENUM该字段也在字段的访问标志中标记。

然后,您需要一个类初始值设定项(一个void名为的无参数方法<clinit>)来创建实例并将它们分配给字段。

但这还不够。注意语言规范,它指定了两个隐式声明方法的存在。

  /**
  * 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);
Run Code Online (Sandbox Code Playgroud)

这是编译器的职责。字节码生成工具将它们的实现插入到特定的枚举类型中。请注意,尽管是编译器生成的,但不应将这两种方法标记为合成的


该规范没有解决反射将如何收集其信息的问题。它可以遍历标记的字段并读取它们,以组装一个数组,或者它可以只调用values()特定类型的方法。因此,您不能省略任何这些工件,也不能values()仅通过委托来实现该方法Class.getEnumConstants()