【问题标题】:From whence cometh Enum.values()?Enum.values() 从何而来?
【发布时间】:2010-10-06 19:36:14
【问题描述】:

我正在查看文档和源代码,因为我想确定 values() 将始终按照 Enum 值的声明顺序返回一个数组。结果,据我所知,它不是in the documentation

我检查了 Enum 类的源代码,但没有运气 (there is a related, private "getValues" method)。

所以我猜测某些编译器/解释器 foo 已经在创建一个类,该类将 Enum 从如下声明中扩展出来:

public static enum MyEnum

那么 values() 在编译期间是否也静态转换为硬编码数组?或者它实际上是在运行时调用的方法,如果是,它定义在哪里?

【问题讨论】:

  • 如果你这么在意,这可能意味着如果在你的枚举声明中移动东西,某些东西会中断。那真的很脆弱。所以我想说,如果你在乎,你可能有一个奇怪的设计。为什么它们井井有条对你很重要?
  • @Mark Peters - 因为我在多个地方使用枚举来订购菜单项。当然,我可以创建某种排序函数,以某种顺序返回它们……但是为什么呢?如果我移动它们不会中断,它只会改变它们在整个应用中的显示顺序。

标签: java android enums


【解决方案1】:

values() 方法是enum 类型定义的一部分。不要与Enum 基类混淆。正式定义在 Section 8.9 of the JLS 中,它指定返回的顺序与声明它们的顺序相匹配。

【讨论】:

  • 完美,这就是我的假设。谢谢!
【解决方案2】:

从下面通过反汇编枚举获得的字节码可以看出,枚举上的values() 方法只是返回包含所有声明的枚举常量的private static 数组的副本。这个数组ENUM$VALUES 填充在一个静态初始化块中。

DaysOfTheWeek.java

public enum DaysOfTheWeek {
    MONDAY,
    TUESDAY,
    WEDNESDAY,
    THURSDAY,
    FRIDAY,
    SATURDAY,
    SUNDAY
}

DaysOfTheWeek.java 反汇编

在静态块之后,标记为 0-92 的字节码初始化枚举常量,标记为 94-139 的字节码将这些常量放入数组中,标记为 140 的字节码将数组分配给类的 ENUM$VALUES 静态字段。 values() 方法中的代码只是通过调用System.arraycopy 来创建分配给ENUM$VALUES 字段的数组的副本并返回该副本。

Compiled from "DaysOfTheWeek.java"
public final class DaysOfTheWeek extends java.lang.Enum{
public static final DaysOfTheWeek MONDAY;

public static final DaysOfTheWeek TUESDAY;

public static final DaysOfTheWeek WEDNESDAY;

public static final DaysOfTheWeek THURSDAY;

public static final DaysOfTheWeek FRIDAY;

public static final DaysOfTheWeek SATURDAY;

public static final DaysOfTheWeek SUNDAY;

static {};
  Code:
   0:   new #1; //class DaysOfTheWeek
   3:   dup
   4:   ldc #18; //String MONDAY
   6:   iconst_0
   7:   invokespecial   #19; //Method "<init>":(Ljava/lang/String;I)V
   10:  putstatic   #23; //Field MONDAY:LDaysOfTheWeek;
   13:  new #1; //class DaysOfTheWeek
   16:  dup
   17:  ldc #25; //String TUESDAY
   19:  iconst_1
   20:  invokespecial   #19; //Method "<init>":(Ljava/lang/String;I)V
   23:  putstatic   #26; //Field TUESDAY:LDaysOfTheWeek;
   26:  new #1; //class DaysOfTheWeek
   29:  dup
   30:  ldc #28; //String WEDNESDAY
   32:  iconst_2
   33:  invokespecial   #19; //Method "<init>":(Ljava/lang/String;I)V
   36:  putstatic   #29; //Field WEDNESDAY:LDaysOfTheWeek;
   39:  new #1; //class DaysOfTheWeek
   42:  dup
   43:  ldc #31; //String THURSDAY
   45:  iconst_3
   46:  invokespecial   #19; //Method "<init>":(Ljava/lang/String;I)V
   49:  putstatic   #32; //Field THURSDAY:LDaysOfTheWeek;
   52:  new #1; //class DaysOfTheWeek
   55:  dup
   56:  ldc #34; //String FRIDAY
   58:  iconst_4
   59:  invokespecial   #19; //Method "<init>":(Ljava/lang/String;I)V
   62:  putstatic   #35; //Field FRIDAY:LDaysOfTheWeek;
   65:  new #1; //class DaysOfTheWeek
   68:  dup
   69:  ldc #37; //String SATURDAY
   71:  iconst_5
   72:  invokespecial   #19; //Method "<init>":(Ljava/lang/String;I)V
   75:  putstatic   #38; //Field SATURDAY:LDaysOfTheWeek;
   78:  new #1; //class DaysOfTheWeek
   81:  dup
   82:  ldc #40; //String SUNDAY
   84:  bipush  6
   86:  invokespecial   #19; //Method "<init>":(Ljava/lang/String;I)V
   89:  putstatic   #41; //Field SUNDAY:LDaysOfTheWeek;
   92:  bipush  7
   94:  anewarray   #1; //class DaysOfTheWeek
   97:  dup
   98:  iconst_0
   99:  getstatic   #23; //Field MONDAY:LDaysOfTheWeek;
   102: aastore
   103: dup
   104: iconst_1
   105: getstatic   #26; //Field TUESDAY:LDaysOfTheWeek;
   108: aastore
   109: dup
   110: iconst_2
   111: getstatic   #29; //Field WEDNESDAY:LDaysOfTheWeek;
   114: aastore
   115: dup
   116: iconst_3
   117: getstatic   #32; //Field THURSDAY:LDaysOfTheWeek;
   120: aastore
   121: dup
   122: iconst_4
   123: getstatic   #35; //Field FRIDAY:LDaysOfTheWeek;
   126: aastore
   127: dup
   128: iconst_5
   129: getstatic   #38; //Field SATURDAY:LDaysOfTheWeek;
   132: aastore
   133: dup
   134: bipush  6
   136: getstatic   #41; //Field SUNDAY:LDaysOfTheWeek;
   139: aastore
   140: putstatic   #43; //Field ENUM$VALUES:[LDaysOfTheWeek;
   143: return

public static DaysOfTheWeek[] values();
  Code:
   0:   getstatic   #43; //Field ENUM$VALUES:[LDaysOfTheWeek;
   3:   dup
   4:   astore_0
   5:   iconst_0
   6:   aload_0
   7:   arraylength
   8:   dup
   9:   istore_1
   10:  anewarray   #1; //class DaysOfTheWeek
   13:  dup
   14:  astore_2
   15:  iconst_0
   16:  iload_1
   17:  invokestatic    #51; //Method java/lang/System.arraycopy:(Ljava/lang/Object;ILjava/lang/Object;II)V
   20:  aload_2
   21:  areturn

public static DaysOfTheWeek valueOf(java.lang.String);
  Code:
   0:   ldc #1; //class DaysOfTheWeek
   2:   aload_0
   3:   invokestatic    #59; //Method java/lang/Enum.valueOf:(Ljava/lang/Class;Ljava/lang/String;)Ljava/lang/Enum;
   6:   checkcast   #1; //class DaysOfTheWeek
   9:   areturn

}

【讨论】:

    【解决方案3】:

    我将在 Devon 的回答中添加 values() 方法是由编译器根据定义添加的。
    来自枚举tutorial

    编译器会自动添加一些 创建时的特殊方法 枚举。例如,它们有一个静态 返回数组的 values 方法 包含所有的值 按照声明的顺序枚举。

    【讨论】:

      【解决方案4】:

      您提供的链接(其中有一个私有 getValues 方法)来自 Apache Harmony(版本 6,它是一个开源 Java SE)。它们与 Oracle 的 Enum 类(没有私有 getValues 方法)有不同的实现。

      Oracle java(撰写本文时版本为 1.6.0-21)具有 valueOf(Class&lt;T&gt; enumType, String name)。这是它的实现:

       /**
           * Returns the enum constant of the specified enum type with the
           * specified name.  The name must match exactly an identifier used
           * to declare an enum constant in this type.  (Extraneous whitespace
           * characters are not permitted.) 
           *
           * @param enumType the <tt>Class</tt> object of the enum type from which
           *      to return a constant
           * @param name the name of the constant to return
           * @return the enum constant of the specified enum type with the
           *      specified name
           * @throws IllegalArgumentException if the specified enum type has
           *         no constant with the specified name, or the specified
           *         class object does not represent an enum type
           * @throws NullPointerException if <tt>enumType</tt> or <tt>name</tt>
           *         is null
           * @since 1.5
           */
          public static <T extends Enum<T>> T valueOf(Class<T> enumType,
                                                      String name) {
              T result = enumType.enumConstantDirectory().get(name);
              if (result != null)
                  return result;
              if (name == null)
                  throw new NullPointerException("Name is null");
              throw new IllegalArgumentException(
                  "No enum const " + enumType +"." + name);
          }
      

      本质上,Apache 实现 valueOf 的方式不同。


      Enum(或enum)有一个名为values() 的公共静态方法,它返回enum 中声明的枚举值常量。这是由编译器填充的。

      【讨论】:

      • Shiver 看到“Oracle 的 Enum 类”或“Oracle Java”,我仍然感到毛骨悚然。让我觉得你在谈论他们为在 Oracle 数据库中使用而制造的 JVM。
      • 保持名称更改,直到 Oracle 真正为 java 做了一些重要的事情。
      • LOL....如果你还没有注意到,大多数sun.com 网站现在是oracle.com。还不如采纳....
      • 哈,是的,我刚刚搜索了一下。我正在使用具有相同 getValues 方法的 Android。
      猜你喜欢
      • 2016-04-01
      • 1970-01-01
      • 2012-01-20
      • 2016-11-03
      • 2011-01-09
      • 2014-08-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多