Java 列举:为什么?什么时候

Java 列举:为什么?什么时候,java,enums,enumeration,Java,Enums,Enumeration,我是一名即将毕业的计算机科学专业的学生,在我的编码生涯中,我发现很少有使用枚举的例子,除了代表一副标准卡片的面这样的典型例子之外 你知道在日常编码中使用枚举的聪明方法吗 为什么枚举如此重要?在什么情况下,人们应该能够确定构建枚举是最好的方法?我想你说的是枚举,而不是枚举 枚举非常适合应用程序中可能使用“幻数字符串”或“幻数”的任何地方 最容易理解其用法的领域是文件访问。枚举中表示每个文件访问模式(读、写、附加)。如果您使用的是“神奇数字”,则可能会出现如下情况: public static cl

我是一名即将毕业的计算机科学专业的学生,在我的编码生涯中,我发现很少有使用枚举的例子,除了代表一副标准卡片的面这样的典型例子之外


你知道在日常编码中使用枚举的聪明方法吗


为什么枚举如此重要?在什么情况下,人们应该能够确定构建枚举是最好的方法?

我想你说的是枚举,而不是枚举

枚举非常适合应用程序中可能使用“幻数字符串”或“幻数”的任何地方

最容易理解其用法的领域是文件访问。枚举中表示每个文件访问模式(读、写、附加)。如果您使用的是“神奇数字”,则可能会出现如下情况:

public static class Constants
{
    public static final int FILEMODE_READ = 1;
    public static final int FILEMODE_WRITE = 2;
    public static final int FILEMODE_APPEND = 3;
}
当您可以使用枚举更清楚、简洁地表达意图时:

public enum FileMode
{
    Read,
    Write,
    Append
}

默认答案:所有Java开发人员都应该明确阅读。在Java 1.5之前,有一章介绍了enum

您将定义为
String
/
int
常量的内容,现在您应该定义为enum。例如,与其拥有:

public class StatusConstants {
   public int ACTIVE = 1;
   public int SUSPENDED = 2;
   public int TEMPORARY_INACTIVE = 3;
   public int NOT_CONFIRMED = 4;
}
您现在有了一个更安全、更友好的开发人员界面:

public enum Status {
   ACTIVE, SUSPENDED, TEMPORARY_INACTIVE, NOT_CONFIRMED
}
任何具有多个选项的情况都是如此,如状态、街道类型(街道、街道、道路等)、用户访问级别(管理员、版主、普通用户)等


查看更多示例和解释。

考虑一些简单的代码:

没有枚举:

 int OPT_A_ON = 1;
 int OPT_A_OFF = 0;

 int OPT_B_ON = 1;
 int OPT_B_OFF = 0;

 SetOption(OPT_A_ON, OPT_B_OFF);    // Declaration: SetOption(int, int)
看起来不错吧?除了SetOptions()需要先选择选项B,然后选择选项A。这将很好地通过编译器,但在运行时,会向后设置选项

现在,使用枚举:

  enum OptA {On =1, Off = 0};
  enum OptB {On =1, Off = 0};

  SetOption(OptA.On, OptB.Off);// Declaration: SetOption(OptB, OptA)
现在我们犯同样的错误,但这次,由于枚举是不同的类型,编译器会发现错误


(注意:我不是一个真正的Java程序员,所以请原谅一些小的语法错误)

枚举非常适合表示某事物的状态。我经常使用枚举,例如:

public enum PlayerState {
    WALKING, STANDING, JUMPING...
}

枚举和派生类之间总是要保持平衡。举一个简单的例子,考虑一个<代码> CAT/COM>类。代码>猫有不同程度的敌意。因此,我们可以创建派生类HostileCat,
FriendlyCat
,等等。然而,也有不同类型的猫,
狮子
老虎
,等等。突然,我们有了一大堆
对象。因此,另一种解决方案是在
Cat
类中提供
枚举,这减少了派生类的数量和总体复杂性。

正如Manuel Selva所建议的,阅读有效的Java第二版,但也阅读singleton部分使用enum是拥有干净的单例对象的最简单方法

这些是的主要参数,通过简短的示例

enum
在Java6中,是一个凌乱类的示例,它可以从使用
enum
(以及其他改进)中受益匪浅

当前,日历定义了以下常量():

这些都是
int
,尽管它们显然代表不同的概念实体

以下是一些严重后果:

  • 它很脆;需要时,必须注意分配不同的号码。
    • 如果我们错误地设置了
      MONDAY=0
      SUNDAY=0,那么我们有
      周一==周日
  • 没有名称空间,也没有类型安全性,因为所有内容都只是一个
    int
    • 我们可以
      setMonth(一月)
      ,但我们也可以
      setMonth(周四)
      setMonth(42)
    • 谁知道(真正的方法!)能做什么
相比之下,我们可以采用类似的方式:

// Hypothetical enums for a Calendar library
enum Month {
   JANUARY, FEBRUARY, ...
}
enum DayOfWeek {
   SUNDAY, MONDAY, ...
}
现在我们不必担心
MONDAY==SUNDAY
(这永远不会发生!),因为
Month
DayOfWeek
是不同的类型,
setMonth(MONDAY)
不会编译

此外,以下是一些前后代码:

// BEFORE with int constants
for (int month = JANUARY; month <= DECEMBER; month++) {
   ...
}

实例字段的情况 在Java中,
enum
是一个具有许多特殊属性的
类,但仍然是一个
类,允许您在必要时定义实例方法和字段

考虑以下示例:

// BEFORE: with int constants
public static final int NORTH = 0;
public static final int EAST  = 1;
public static final int SOUTH = 2;
public static final int WEST  = 3;

public static int degreeFor(int direction) {
   return direction * 90; // quite an assumption!
   // must be kept in-sync with the int constants!
}

//...
for (int dir = NORTH; dir <= WEST; dir++) {
   ... degreeFor(dir) ...
}
static int apply(int op1, int op2, int operator) {
   switch (operator) {
      case PLUS  : return op1 + op2;
      case MINUS : return op1 - op2;
      case ...
      default: throw new IllegalArgumentException("Unknown operator!");
   }
}
实例方法的例子 考虑以下示例:

// BEFORE: with int constants
public static final int NORTH = 0;
public static final int EAST  = 1;
public static final int SOUTH = 2;
public static final int WEST  = 3;

public static int degreeFor(int direction) {
   return direction * 90; // quite an assumption!
   // must be kept in-sync with the int constants!
}

//...
for (int dir = NORTH; dir <= WEST; dir++) {
   ... degreeFor(dir) ...
}
static int apply(int op1, int op2, int operator) {
   switch (operator) {
      case PLUS  : return op1 + op2;
      case MINUS : return op1 - op2;
      case ...
      default: throw new IllegalArgumentException("Unknown operator!");
   }
}
如前一个示例所示,Java中的
enum
可以有实例方法,但不仅如此,每个常量还可以有自己特定的
@Override
。这在以下代码中显示:

enum Operator {
    PLUS  { int apply(int op1, int op2) { return op1 + op2; } },
    MINUS { int apply(int op1, int op2) { return op1 - op2; } },
    ...
    ;
    abstract int apply(int op1, int op2);
}

EnumMap
这里引用了《有效Java第二版》中的一段话:

切勿从枚举中派生与枚举关联的值;而是将其存储在实例字段中。(第31项:使用实例字段而不是序数)使用序数索引数组很少合适:请改用
EnumMap
。一般原则是应用程序程序员应该很少(如果有的话)使用
Enum.ordinal
。(第33项:使用
EnumMap
代替顺序索引)

基本上,与以前一样,您可能会遇到以下情况:

enum Direction {
   NORTH(0), EAST(90), SOUTH(180), WEST(270);
   // so obvious! so easy to read! so easy to write! so easy to maintain!

   private final int degree;
   Direction(int degree)      { this.degree = degree; }
   public int getDegree()     { return degree; }
}

//...
for (Direction dir : Direction.values()) {
   ... dir.getDegree() ...
}
// BEFORE, with int constants and array indexing
Employee[] employeeOfTheMonth = ...

employeeOfTheMonth[JANUARY] = jamesBond;
public static final int BUTTON_A = 1;
public static final int BUTTON_B = 2;
public static final int BUTTON_X = 4;
public static final int BUTTON_Y = 8;

int buttonState = BUTTON_A | BUTTON_X; // A & X are pressed!

if ((buttonState & BUTTON_B) != 0) {   // B is pressed...
   ...
}
enum Button {
  A, B, X, Y;
}

Set<Button> buttonState = EnumSet.of(Button.A, Button.X); // A & X are pressed!

if (buttonState.contains(Button.B)) { // B is pressed...
   ...
}
现在您可以拥有:

// AFTER, with enum and EnumMap
Map<Month, Employee> employeeOfTheMonth = ...

employeeOfTheMonth.put(Month.JANUARY, jamesBond);
使用
enum
EnumSet
,可以看到如下情况:

enum Direction {
   NORTH(0), EAST(90), SOUTH(180), WEST(270);
   // so obvious! so easy to read! so easy to write! so easy to maintain!

   private final int degree;
   Direction(int degree)      { this.degree = degree; }
   public int getDegree()     { return degree; }
}

//...
for (Direction dir : Direction.values()) {
   ... dir.getDegree() ...
}
// BEFORE, with int constants and array indexing
Employee[] employeeOfTheMonth = ...

employeeOfTheMonth[JANUARY] = jamesBond;
public static final int BUTTON_A = 1;
public static final int BUTTON_B = 2;
public static final int BUTTON_X = 4;
public static final int BUTTON_Y = 8;

int buttonState = BUTTON_A | BUTTON_X; // A & X are pressed!

if ((buttonState & BUTTON_B) != 0) {   // B is pressed...
   ...
}
enum Button {
  A, B, X, Y;
}

Set<Button> buttonState = EnumSet.of(Button.A, Button.X); // A & X are pressed!

if (buttonState.contains(Button.B)) { // B is pressed...
   ...
}
enum按钮{
A、 B,X,Y;
}
Set buttonState=EnumSet.of(Button.A,Button.X);//按下A&X键!
如果按下(buttonState.contains(Button.B)){//B。。。
...
}
工具书类
  • --比较完整,有很多例子
另见
  • 有效Java第二版
    • 第30项:使用
      enum
      而不是
      int
      常量
    • 项目31:使用