【问题标题】:Java enumerations vs. static constantsJava 枚举与静态常量
【发布时间】:2011-01-14 19:37:03
【问题描述】:

我正在查看一些由公司其他部门维护的 Java 代码,顺便提一下,一些前 C 和 C++ 开发人员。普遍存在的一件事是使用静态整数常量,例如

class Engine {
    private static int ENGINE_IDLE = 0;
    private static int ENGINE_COLLECTING = 1;
    ...
}

除了缺少“final”限定符之外,我对这种代码有点困扰。我希望看到,在学校主要接受 Java 培训,会更像

class Engine {
    private enum State { Idle, Collecting };
    ...
}

但是,我的论点失败了。为什么,如果有的话,后者比前者更好?

【问题讨论】:

  • +1 用于制作常量final

标签: java arguments


【解决方案1】:

Lajcik 引用的规范中的原因在 Josh Bloch 的 Effective Java,第 30 条中有更详细的解释。如果您可以访问该书,我建议您仔细阅读它。 Java 枚举是成熟的类,这就是您获得编译时类型安全的原因。你也可以给他们行为,给你更好的封装。

【讨论】:

    【解决方案2】:

    枚举还为您提供了很大的灵活性。由于枚举本质上是类,因此您可以使用有用的方法来扩充它们(例如提供与枚举中的某个值对应的国际化资源字符串、在枚举类型的实例和可能需要的其他表示形式之间来回转换等)。 )

    【讨论】:

      【解决方案3】:

      摘自官方文档http://java.sun.com/j2se/1.5.0/docs/guide/language/enums.html

      这个模式有很多问题,比如:

      • 不是类型安全的 - 由于季节只是一个 int,因此您可以在需要季节时传入任何其他 int 值,或者将两个季节相加(这没有意义)。
      • 无命名空间 - 您必须在 int 枚举的常量前面加上一个字符串(在本例中为 SEASON_)以避免与其他 int 枚举类型发生冲突。
      • 脆弱 - 因为 int 枚举是编译时常量,所以它们被编译到使用它们的客户端中。如果在两个现有常量之间添加新常量或更改顺序,则必须重新编译客户端。如果不是,它们仍会运行,但它们的行为将是未定义的。
      • 打印的值不提供信息 - 因为它们只是整数,所以如果您打印一个,您得到的只是一个数字,它不会告诉您它代表什么,甚至它是什么类型。

      这几乎涵盖了它。一个词的论点是枚举更具可读性和信息量。

      还有一点是枚举,就像类一样。可以有字段和方法。这使您可以选择在枚举本身中包含有关每种状态类型的一些附加信息。

      【讨论】:

        【解决方案4】:
        1. 可读性 - 当您使用枚举并执行State.Idle 时,读者会立即知道您在谈论空闲状态。将此与 4 或 5 进行比较。

        2. 类型安全 - 使用枚举时,即使是错误的用户也不能传递错误的值,因为编译器会强制他使用枚举中预先声明的值之一。如果是简单的整数,他甚至可以通过 -3274。

        3. 可维护性 - 如果您想添加新状态 Waiting,那么通过在枚举状态中添加常量 Waiting 来添加新状态将非常容易,不会造成任何混乱。

        【讨论】:

          【解决方案5】:

          有一种情况是首选静态常量(而不是代码是具有大量依赖关系的遗留代码),即该值的成员不是/以后可能不是有限的。

          想象一下,如果您以后可以添加新状态,例如 Collected。使用枚举执行此操作的唯一方法是编辑原始代码,如果在已经有很多代码操作它的情况下完成修改,这可能会出现问题。除此之外,我个人认为没有理由不使用枚举。

          只是我的想法。

          【讨论】:

          • 但是,添加新状态可能需要对代码进行其他更改(即处理该新状态)。所以出现这种情况的可能性不大。遗留代码可能是唯一适合这种方法的地方。
          【解决方案6】:

          为什么,如果有的话,后者更好 比前者?

          这要好得多,因为它为您提供了类型安全性并且是自记录的。对于整数常量,您必须查看 API 文档以找出哪些值是有效的,并且没有什么可以阻止您使用无效值(或者更糟糕的是,完全不相关的整数常量)。使用 Enums,方法签名会直接告诉您哪些值是有效的(IDE 自动完成将起作用)并且不可能使用无效值。

          不幸的是,“整数常量枚举”模式非常普遍,即使在 Java 标准 API(并从那里广泛复制)中也是如此,因为 Java 在 Java 5 之前没有枚举。

          【讨论】:

          • +1 因为你是唯一一个提到自我记录的人。如果你有一个方法,它接受(或返回)一个 int,它代表一些代码,你没有 doc 或 source 就没有机会得出 int 的语义。但是枚举对每个值都有一个名称,并且签名直接(通过类型)连接到枚举。
          【解决方案7】:

          通过使用int 来引用常量,您并没有强迫某人实际使用该常量。因此,例如,您可能有一个采用引擎状态的方法,有人可能会高兴地调用它:

          engine.updateState(1);
          

          使用enum 强制用户坚持使用解释性标签,因此更易读。

          【讨论】:

            【解决方案8】:

            前者在 1.5 之前的代码中很常见。实际上,另一个常见的习惯用法是在接口中定义常量,因为它们没有任何代码。

            【讨论】:

            • 但是这种做法也鼓励使用继承那些常量,这有点难看。 :(
            • @David:这是“整数常量枚举”引起的最小问题。
            • @Michael:但问题仍然存在。
            • @David,是的,这就是为什么他们还在 1.5 之后引入了“import static”。
            【解决方案9】:

            因为枚举提供类型安全。在第一种情况下,您可以传递任何整数,如果您使用枚举,则仅限于 IdleCollecting

            仅供参考:http://www.javapractices.com/topic/TopicAction.do?Id=1.

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2014-06-01
              • 1970-01-01
              • 2014-06-29
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              相关资源
              最近更新 更多