如何用Java内部表示枚举?

时间:2015-09-02 13:09:06

标签: java enums

Java枚举是类。它们被编译为类。

如何编译以下示例? 什么是它的"类版本"? 什么是完全类代码?我想要实际的Java代码。

<s:property value="ABCFormBean.dependentLists[0].lastNameEng"/> 

5 个答案:

答案 0 :(得分:18)

每个enum类都被编译为一个类java.lang.Enum的子类。每个枚举常量在该类中变为static final常量。然后,按照声明的顺序创建一个包含所有枚举常量的数组$VALUES

您可以使用命令javap -p -c Ordinals(在已编译的.class文件中)反汇编代码以查找详细信息。

Compiled from "Ordinals.java"
public final class Ordinals extends java.lang.Enum<Ordinals> {
  public static final Ordinals FIRST;

  public static final Ordinals SECOND;

  public static final Ordinals THIRD;

  private java.lang.String notation; // your custom field

  private static final Ordinals[] $VALUES; // all enum constants

  public static Ordinals[] values(); // every enum class has this static method
    Code:
       0: getstatic     #1                  // Field $VALUES:[LOrdinals;
       3: invokevirtual #2                  // Method "[LOrdinals;".clone:()Ljava/lang/Object;
       6: checkcast     #3                  // class "[LOrdinals;"
       9: areturn       

  public static Ordinals valueOf(java.lang.String); // every enum class has this static method
    Code:
       0: ldc_w         #4                  // class Ordinals
       3: aload_0       
       4: invokestatic  #5                  // Method java/lang/Enum.valueOf:(Ljava/lang/Class;Ljava/lang/String;)Ljava/lang/Enum;
       7: checkcast     #4                  // class Ordinals
      10: areturn       

  private Ordinals(java.lang.String);
    Code:
       0: aload_0       
       1: aload_1       
       2: iload_2       
       3: invokespecial #6                  // Method java/lang/Enum."<init>":(Ljava/lang/String;I)V
       6: aload_0       
       7: aload_3       
       8: putfield      #7                  // Field notation:Ljava/lang/String;
      11: return        

  public java.lang.String getNotation();
    Code:
       0: aload_0       
       1: getfield      #7                  // Field notation:Ljava/lang/String;
       4: areturn       

  static {}; // fills the $VALUES array and initializes the static fields corresponding to the enum constants
    Code:
       0: new           #4                  // class Ordinals
       3: dup           
       4: ldc           #8                  // String FIRST
       6: iconst_0      
       7: ldc           #9                  // String st
       9: invokespecial #10                 // Method "<init>":(Ljava/lang/String;ILjava/lang/String;)V
      12: putstatic     #11                 // Field FIRST:LOrdinals;
      15: new           #4                  // class Ordinals
      18: dup           
      19: ldc           #12                 // String SECOND
      21: iconst_1      
      22: ldc           #13                 // String nd
      24: invokespecial #10                 // Method "<init>":(Ljava/lang/String;ILjava/lang/String;)V
      27: putstatic     #14                 // Field SECOND:LOrdinals;
      30: new           #4                  // class Ordinals
      33: dup           
      34: ldc           #15                 // String THIRD
      36: iconst_2      
      37: ldc           #16                 // String rd
      39: invokespecial #10                 // Method "<init>":(Ljava/lang/String;ILjava/lang/String;)V
      42: putstatic     #17                 // Field THIRD:LOrdinals;
      45: iconst_3      
      46: anewarray     #4                  // class Ordinals
      49: dup           
      50: iconst_0      
      51: getstatic     #11                 // Field FIRST:LOrdinals;
      54: aastore       
      55: dup           
      56: iconst_1      
      57: getstatic     #14                 // Field SECOND:LOrdinals;
      60: aastore       
      61: dup           
      62: iconst_2      
      63: getstatic     #17                 // Field THIRD:LOrdinals;
      66: aastore       
      67: putstatic     #1                  // Field $VALUES:[LOrdinals;
      70: return        
}

这将转换为Java

public final class Ordinals extends java.lang.Enum<Ordinals> {
  public static final Ordinals FIRST;

  public static final Ordinals SECOND;

  public static final Ordinals THIRD;

  private String notation;

  private static final Ordinals[] $VALUES;

  public static Ordinals[] values() {
      return $VALUES.clone();
  }

  public static Ordinals valueOf(String name) {
      return (Ordinals) Enum.valueOf(Ordinals.class, name);
  }

  private Ordinals(String name, int ordinal, String notation) {
      super(name, ordinal);
      this.notation = notation
  }

  static {
      FIRST = new Ordinals("FIRST", 0, "st");
      SECOND = new Ordinals("SECOND", 1, "nd");
      THIRD = new Ordinals("THIRD", 2, "rd");
      Ordinals[] $VALUES = new Ordinals[3];
      $VALUES[0] = FIRST;
      $VALUES[1] = SECOND;
      $VALUES[2] = THIRD;
      Ordinals.$VALUES = $VALUES;
  }
}

类版本与此完全无关 - 它取决于您使用的Java编译器的版本(或编译器上的显式设置,以强制它为较旧的Java版本进行编译)。

答案 1 :(得分:3)

您可以将枚举视为具有类型常量的类。您可以将代码视为:

public enum Ordinals {
    public static final FIRST = "st";
    public static final SECOND = ..;
    // ...

    private String notation;

    private Ordinals(String notation) {
        this.notation = notation;
    }
    public String getNotation() {
        return notation;
    }
}

javap命令可能对您有用,请尝试以下操作:

javap Example.class

public final class Example extends java.lang.Enum<Example> {
  public static final Example FIRST;
  public static final Example SECOND;
  public static final Example THIRD;
  public static Example[] values();
  public static Example valueOf(java.lang.String);
  public java.lang.String getNotation();
  static {};
}

答案 2 :(得分:3)

使用javap - p Ordinals.class命令,您将获得以下代码:

public final class Ordinals extends java.lang.Enum<Ordinals> {
    public static final Ordinals FIRST;
    public static final Ordinals SECOND;
    public static final Ordinals THIRD;
    private java.lang.String notation;
    private static final Ordinals[] $VALUES;
    public static Ordinals[] values();
    public static Ordinals valueOf(java.lang.String);
    private Ordinals(java.lang.String);
    public java.lang.String getNotation();
    static {};
}

因此,enum的每个值都会转换为类类型的public static final字段。如果我理解正确,则在static块中使用private构造函数初始化这些字段,以便

static {
    Ordinals.FIRST = new Ordinals("st");
    Ordinals.SECOND = new Ordinals("nd");
    Ordinals.THIRD = new Ordinals("rd");
    // ...
}

正如Effective Java一书的第3项中所述,enum或多或少与单身人士相似,这反映在上述{的使用中{ {1}}字段。

答案 3 :(得分:2)

Class version是告诉编译类文件的Java版本的原因。你可能对此并不感兴趣。

enum将正常编译,Ordinals隐式扩展Enum类,3个类级别变量,Ordinals类的所有实例。

答案 4 :(得分:1)

javap -private的输出是:

public final class Ordinals extends java.lang.Enum<Ordinals> {
  public static final Ordinals FIRST;
  public static final Ordinals SECOND;
  public static final Ordinals THIRD;
  private java.lang.String notation;
  private static final Ordinals[] $VALUES;
  public static Ordinals[] values();
  public static Ordinals valueOf(java.lang.String);
  private Ordinals(java.lang.String);
  public java.lang.String getNotation();
  static {};
}

如您所见,编译器添加了一些内容。

有一个合成数组$VALUES,只要你调用values()方法,它就会被复制出来。

values()方法本身被添加到类中,以符合每个枚举的要求,即应该有一个静态values()方法返回所有枚举常量的数组。为什么它由编译器添加而不是从Enum()继承?因为它是静态的。

以同样的方式,添加了valueOf。它是通过调用静态Enum.valueOf来实现的。

在这个清单中你没有看到的一件事是构造函数有两个额外的,看不见的参数,它们在枚举常量设置时传递。它们是常数的名称及其序号。它们会从super()传递给Enum构造函数,并用于从中继承的方法name()ordinal()