【问题标题】:What's the use of "enum" in Java? [duplicate]Java中的“枚举”有什么用? [复制]
【发布时间】:2012-04-08 16:21:25
【问题描述】:

所以我研究了这个“枚举”类型,在我看来,它有点像一个美化的数组/ArrayList/List。它的具体用途是什么?

【问题讨论】:

  • 在你看来它在什么方面看起来像一个数组?你不能在里面存储东西,你不能从中取出东西,它不包含任何东西......基本上它没有通常与数组相关联的属性。
  • 链接到我的another answer,有些人觉得这很有用。我知道它在比较 java 枚举和 C++ 枚举的线程中,但我尝试在那里描述 java 枚举属性。
  • @sepp2k:啊,我想我明白了:源代码中的定义有点像列表文字......
  • 枚举不是一个数组,但如果你的枚举是 MyEnum 那么 MyEnum.values() 是一个枚举中所有常量的数组

标签: java enums


【解决方案1】:

枚举类型基本上是一种数据类型,可让您以更易读和更可靠的方式描述类型的每个成员。

下面是一个简单的例子来解释原因:

假设您正在编写一个与季节有关的方法:

int 枚举模式

首先,您声明了一些 int 静态常量来表示每个季节。

public static final int SPRING = 0;
public static final int SUMMER = 1;
public static final int FALL = 2;
public static final int WINTER = 2;

然后,您声明了一个将季节名称打印到控制台的方法。

public void printSeason(int seasonCode) {
    String name = "";
    if (seasonCode == SPRING) {
        name = "Spring";
    }
    else if (seasonCode == SUMMER) {
        name = "Summer";
    }
    else if (seasonCode == FALL) {
        name = "Fall";
    }
    else if (seasonCode == WINTER) {
        name = "Winter";
    }
    System.out.println("It is " + name + " now!");
}

所以,在那之后,你可以像这样打印一个季节名称。

printSeason(SPRING);
printSeason(WINTER);

这是一种非常常见(但不好)的方法,可以为类中不同类型的成员做不同的事情。但是,由于这些代码涉及整数,所以你也可以这样调用方法而没有任何问题。

printSeason(0);
printSeason(1);

甚至像这样

printSeason(x - y);
printSeason(10000);

编译器不会抱怨,因为这些方法调用是有效的,你的printSeason 方法仍然可以工作。

但这里有些不对劲。 10000 的季节代码应该是什么意思?如果x - y 结果为负数怎么办?当您的方法收到一个没有意义且不应该存在的输入时,您的程序对此一无所知。

您可以解决此问题,例如,通过添加额外的检查。

...
else if (seasonCode == WINTER) {
    name = "Winter";
}
else {
    throw new IllegalArgumentException();
}
System.out.println(name);

现在,当季节代码无效时,程序将抛出 RunTimeException。但是,您仍然需要决定如何处理异常。

顺便说一句,你肯定注意到FALLWINTER 的代码都是2,对吧?

你现在应该明白了。这种模式很脆弱。它使您可以在任何地方编写条件检查。如果你正在制作一款游戏,并且想在你的想象世界中添加一个额外的赛季,那么这种模式会让你去了解所有按赛季做事的方法,并且在大多数情况下你会忘记其中的一些。

对于这种情况,您可能认为类继承是一个好主意。但我们只需要其中的一些,仅此而已。

这就是enum 发挥作用的时候。


使用enum 类型

在 Java 中,enum 类型是通过公共静态 final 字段为每个枚举常量导出一个实例的类。

在这里可以声明四个枚举常量:SPRING, SUMMER, FALL, WINTER。每个都有自己的name

public enum Season {
    SPRING("Spring"), SUMMER("Summer"), FALL("Fall"), WINTER("Winter");

    private String name;

    Season(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }
}

现在,回到方法。

public void printSeason(Season season) {
    System.out.println("It is " + season.getName() + " now!");
}

您现在可以使用Season 作为输入,而不是使用int。您可以告诉Season 给您它的名称,而不是条件检查。

这就是你现在使用这个方法的方式:

printSeason(Season.SPRING);
printSeason(Season.WINTER);
printSeason(Season.WHATEVER); <-- compile error

当您使用不正确的输入时,您将收到编译时错误,并且只要程序编译,您就可以保证获得Season 的非空单例引用。

当我们需要额外的季节时,我们只需在 Season 中添加另一个常量即可。

public enum Season {
    SPRING("Spring"), SUMMER("Summer"), FALL("Fall"), WINTER("Winter"), 
    MYSEASON("My Season");

...

当您需要一组固定的常量时,enum 可能是一个不错的选择(但并非总是如此)。这是一个更易读、更可靠、更强大的解决方案。

【讨论】:

    【解决方案2】:

    如果类应该有一个固定的枚举实例数,则使用enum 而不是class

    示例:

    • DayOfWeek = 7 个实例 → enum
    • CardSuit    = 4 个实例 → enum
    • Singleton = 1 个实例   → enum

    • Product      = 可变数量的实例 → class
    • User            = 可变数量的实例 → class
    • Date            = 可变数量的实例 → class

    【讨论】:

    • 也用于应用程序中的语言切换之类的东西,例如菜单名称等
    • 右,当在编译时括号时是已知的:) span>
    • 是的,当然。只需添加一个示例:p
    • 当类的实例具有非常相似或可注入的行为模式时;必须在枚举自己的方法中切换类案例可能是代码异味。
    【解决方案3】:

    1) enum 是面向对象方法中的关键字。

    2) 用于单行编写代码,仅此而已。

         public class NAME
         {
            public static final String THUNNE = "";
            public static final String SHAATA = ""; 
            public static final String THULLU = ""; 
         }
    
    -------This can be replaced by--------
    
      enum NAME{THUNNE, SHAATA, THULLU}
    

    3) 大多数开发者不使用 enum 关键字,它只是一种替代方法..

    【讨论】:

      【解决方案4】:

      Java 编程语言enums 比其他语言中的对应语言强大得多,其他语言只不过是美化的整数。新的枚举声明定义了一个成熟的类(称为枚举类型)。除了解决 java 5.0 之前使用的以下 int Enum 模式存在的所有问题(Not typesafe, No namespace, Brittleness and Printed values are uninformative)之外:

      public static final int SEASON_WINTER = 0;

      它还允许您向枚举类型添加任意方法和字段,以实现任意接口等等。枚举类型提供所有 Object 方法的高质量实现。它们是ComparableSerializable,串行形式旨在承受枚举类型的任意更改。您也可以在 switch 的情况下使用 Enum。

      阅读有关 Java 枚举http://docs.oracle.com/javase/1.5.0/docs/guide/language/enums.html 的完整文章了解更多详细信息。

      【讨论】:

      • 但有时我想要的只是一组美化的整数
      【解决方案5】:

      枚举类型是一种类型,其字段由一组固定的常量组成。常见示例包括指南针方向(NORTH、SOUTH、EAST 和 WEST 的值)和星期几。

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

      您应该在需要表示一组固定常量的任何时候使用枚举类型。这包括自然枚举类型,例如我们太阳系中的行星和您在编译时知道所有可能值的数据集——例如,菜单上的选项、命令行标志等等。

      这里有一些代码向您展示如何使用上面定义的 Day 枚举:

      public class EnumTest {
          Day day;
      
          public EnumTest(Day day) {
              this.day = day;
          }
      
          public void tellItLikeItIs() {
              switch (day) {
                  case MONDAY:
                      System.out.println("Mondays are bad.");
                      break;
      
                  case FRIDAY:
                      System.out.println("Fridays are better.");
                      break;
      
                  case SATURDAY: case SUNDAY:
                      System.out.println("Weekends are best.");
                      break;
      
                  default:
                      System.out.println("Midweek days are so-so.");
                      break;
              }
          }
      
          public static void main(String[] args) {
              EnumTest firstDay = new EnumTest(Day.MONDAY);
              firstDay.tellItLikeItIs();
              EnumTest thirdDay = new EnumTest(Day.WEDNESDAY);
              thirdDay.tellItLikeItIs();
              EnumTest fifthDay = new EnumTest(Day.FRIDAY);
              fifthDay.tellItLikeItIs();
              EnumTest sixthDay = new EnumTest(Day.SATURDAY);
              sixthDay.tellItLikeItIs();
              EnumTest seventhDay = new EnumTest(Day.SUNDAY);
              seventhDay.tellItLikeItIs();
          }
      }
      

      输出是:

      星期一很糟糕。
      周中的日子一般。
      星期五 更好。
      周末最好。
      周末最好。

      Java 编程语言枚举类型比其他语言中的枚举类型强大得多。枚举声明定义了一个类(称为枚举类型)。枚举类主体可以包括方法和其他字段。编译器在创建枚举时会自动添加一些特殊方法。例如,它们有一个静态值方法,该方法返回一个数组,该数组按照声明的顺序包含枚举的所有值。此方法通常与 for-each 构造结合使用,以迭代枚举类型的值。例如,下面 Planet 类示例中的这段代码迭代了太阳系中的所有行星。

      for (Planet p : Planet.values()) {
          System.out.printf("Your weight on %s is %f%n",
                            p, p.surfaceWeight(mass));
      }
      

      除了它的属性和构造函数之外,Planet 还有一些方法可以让您检索每个行星上物体的表面重力和重量。这是一个示例程序,它计算您在地球上的重量(以任何单位)并计算并打印您在所有行星上的重量(以同一单位):

      public enum Planet {
          MERCURY (3.303e+23, 2.4397e6),
          VENUS   (4.869e+24, 6.0518e6),
          EARTH   (5.976e+24, 6.37814e6),
          MARS    (6.421e+23, 3.3972e6),
          JUPITER (1.9e+27,   7.1492e7),
          SATURN  (5.688e+26, 6.0268e7),
          URANUS  (8.686e+25, 2.5559e7),
          NEPTUNE (1.024e+26, 2.4746e7);
      
          private final double mass;   // in kilograms
          private final double radius; // in meters
          Planet(double mass, double radius) {
              this.mass = mass;
              this.radius = radius;
          }
          private double mass() { return mass; }
          private double radius() { return radius; }
      
          // universal gravitational constant  (m3 kg-1 s-2)
          public static final double G = 6.67300E-11;
      
          double surfaceGravity() {
              return G * mass / (radius * radius);
          }
          double surfaceWeight(double otherMass) {
              return otherMass * surfaceGravity();
          }
          public static void main(String[] args) {
              if (args.length != 1) {
                  System.err.println("Usage: java Planet <earth_weight>");
                  System.exit(-1);
              }
              double earthWeight = Double.parseDouble(args[0]);
              double mass = earthWeight/EARTH.surfaceGravity();
              for (Planet p : Planet.values())
                 System.out.printf("Your weight on %s is %f%n",
                                   p, p.surfaceWeight(mass));
          }
      }
      

      如果您从命令行使用参数 175 运行 Planet.class,您会得到以下输出:

      $ java Planet 175
      你在 MERCURY 上的体重是 66.107583
      你的 金星上的体重是 158.374842
      你在地球上的体重是 175.000000
      你在火星上的体重是 66.279007
      你在木星上的体重是 442.847567
      你在土星上的体重是 186.552719
      你 URANUS 上的重量是 158.397260
      你在 NEPTUNE 上的重量是 199.207413

      来源:http://docs.oracle.com/javase/tutorial/java/javaOO/enum.html

      【讨论】:

      • 你至少可以写一个源码,因为你复制粘贴了官方文档,没有做任何改动。
      • 冷静点,我只是专注于帮助他而已!现在附上源链接!!!!!!
      • 老实说,该文本的开头是一个颇具误导性的陈述。一个枚举可以有更多的字段,而不仅仅是一组常量。
      • 是的,你是对的,可能是这样,但如果你继续阅读,你会发现更多关于枚举的描述,可以详细说明它的使用。
      【解决方案6】:

      枚举作为一种固定数量的常量,至少可以用于两件事

      常数

      public enum Month {
          JANUARY, FEBRUARY, ...
      }
      

      这比创建一堆整数常量要好得多。

      创建单例

      public enum Singleton {
          INSTANCE
      
         // init
      };
      

      你可以用枚举做一些很有趣的事情,看看here

      另请查看official documentation

      【讨论】:

      • 这两件事几乎是一回事。单例也是一个“常数”,不是吗?
      • @aioobe 它向您展示了枚举用作单例的方式。第一个例子(常量)是一个固定的常量列表。另一方面,这个类的行为更像一个普通类,但 Java 本身确保这个类只创建一次。
      • 啊,但是你也可以把两个参数反过来:单例是一个固定的常量列表,Month 枚举就像一个普通类,除了 Java 确保这个类只被实例化了 12 次。你说“至少可以用于两件事”,我说这两件事是一回事。 :-) 你不同意吗?
      • @Tomas 我不会说Singleton 的用法“完全不同”。程序员的意图可能不同,因为单例通常在应用程序中扮演更大的角色,而多值枚举通常是一些小的特定细节。也许这就是您的评论所要表达的意思。但从技术上讲,Singleton 枚举只是一个“固定的常量列表”,恰好只有一个元素。正如 aioobe 所问,从技术上讲,此答案中的两个示例完全相同;一个是有 12 个值的枚举,另一个是 1 个值。
      【解决方案7】:

      枚举是recommended way,为已定义的一组内容提供易于记忆的名称(也可选择一些有限的行为)。

      你应该使用枚举,否则你会使用多个静态整数常量(例如public static int ROLE_ADMIN = 0BLOOD_TYPE_AB = 2

      使用枚举代替枚举的主要优点是类型安全、在尝试使用错误值时编译类型警告/错误以及为相关“常量”提供命名空间。此外,它们更易于在 IDE 中使用,因为它也有助于代码完成。

      【讨论】:

        【解决方案8】:

        枚举是一种安全类型,因此您不能在运行时分配新值。此外,您可以在 switch 语句中使用它(如 int)。

        【讨论】:

        • 我没有得到这个答案。普通类也是类型安全的。如果您将它与使用整数进行比较,那么为什么要强调可以在开关中使用它们的事实呢?!
        • 在 switch 中使用 Enum 比使用 Integer 更优雅。
        • switch(i) { ... case 11: delete();休息; ... } switch(actions) { ... case DELETE: delete();休息; ... } 哪个代码最干净?枚举,不是吗?
        • 你不使用 named 常量,比如你的代码中的 public static int DELETE = 11 吗? (对于那些这样做的人,switch 语句看起来与 enum 的情况相同。)
        • 如果您在开关中使用枚举,那么您做错了 - 将其反转以使代码在枚举中。 enum.doThings(stuff) 比 switch(enum) { case THING1: { } case THING2: {} } 更容易阅读 - 它还降低了圈复杂度,从而更容易阅读和测试代码。
        猜你喜欢
        • 2014-04-28
        • 2012-07-08
        • 1970-01-01
        • 2016-10-02
        • 1970-01-01
        • 2015-12-31
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多