Java是否存在可变性用例和可能性?

时间:2012-10-22 16:40:59

标签: java spring enums

我不知道我是否是唯一知道这一点的人,但是枚举的值并非隐含最终且可以修改。

  enum EnumTest {
    TOTO("TOTO 1"),
    TATA("TATA 2"),
    ;

    private String str;

    private EnumTest(String str) {
      this.str = str;
    }

    @Override
    public String toString() {
      return str;
    }
  }

  public static void main(String[] args) {
    System.out.println(EnumTest.TATA);
    EnumTest.TATA.str = "newVal";
    System.out.println(EnumTest.TATA);
  }

TATA 2
newVal

这些值通常在实例创建时初始化(TOTO("TOTO 1")),但除了我自己之外,我从未见过有人使用final关键字来表示应该是不可变的枚举变量。这不是问题的关键,只是想知道我是否是唯一意识到这一点的人。


我想知道的是,是否有任何用例来创建可变的枚举?

我也想知道我们可以用枚举做的限制(良好做法与否)。 我没有测试它,但也许枚举可以注入Spring bean? 至少我们似乎可以为每个实例添加注释(@Deprecated可以正常工作)以及方法。

8 个答案:

答案 0 :(得分:8)

一个可能的用例是延迟初始化(在首次使用时计算一些字段值,如果通常根本不使用它们),或者是“普通”可变单例对象(如注册表等)。

但在大多数情况下,枚举对象应该是不可变的,并且它们的字段是最终的。

答案 1 :(得分:7)

虽然你在这里指出一个有趣的事实,但就我而言,可变的枚举字段没有用处。有很多理由说明为什么使用这种语言“功能”(“bug”?)会是一个坏主意,尤其是可能会让其他开发人员感到困惑。

答案 2 :(得分:3)

在回应Alex D的回答和评论时,我正在考虑发布一个可能的用例。让我们采用行星的旧标准枚举示例,从中可以计算出重力等。想象一下,你想要保持每个星球上的人类殖民地数量。是的,你可以使用EnumMap,但我可以看到一个案例,可能需要越来越多的可变字段,并且每个值都有一个单独的映射,或者一个单独的类来保存与枚举相关的可变值将是违反直觉的。

正如我在评论中所说,一般来说,我认为枚举通常是并且应该是不可改变的,但我觉得说没有用例太强大了。

答案 3 :(得分:1)

我认为没有理由禁止在enum中使用可变字段。一个人使用enum来声明该类型的值属于有限(和已知)可能性之一。这并不意味着这些值不能具有随时间演变的属性。

有些人要求针对这种情况使用案例。一个示例是使用enum类型,例如ErrorCategory,它会将错误归类为任意数量的预定义类别之一(例如:DocumentationErrorSemanticError,{ {1}} ...)。

假设那些LayoutError具有ErrorCategoriesrequiresInstantIntervention等属性。我可以想象这些属性的价值可能会随着时间的推移而改变,或者它们可以由用户配置。

我意识到有(很多)其他方法可以实现这一点(例如上面提到的确实shouldFailBuild)并且人们可以总是争论风格,但对我来说,EnumMaps s的这种用法本身并没有错。由于enum是java中的引用类型,enum的行为保持不变,就像第一个地方没有可变属性一样。

答案 4 :(得分:0)

枚举实例是枚举类的公共静态final字段。因此,如果它是可变的,您可以在另一个线程中修改其状态。这可能不是你想要的,如果你没有意识到这一点,可能会引起问题。

答案 5 :(得分:0)

我使用一个可变的枚举来处理要在使用和中继时保留的控件之外的序列化数值。例如

VALUE_A = 1
VALUE_B = 13
VALUE_C = 17
VALUE_UNRECOGNIZED

例如如果我收到序列化值61怎么办?我不认识它,所以我没有一个枚举常量,我不处理它,但是我不想失败:我想保留序列化的值并传递它。

也许规范的方法可能是创建一个具有两个字段的新类:一个不变的枚举和原始值,但是恕我直言,这似乎比较麻烦。

答案 6 :(得分:0)

更正我,如果我错了,但是枚举是Java中在应用程序的整个生命周期中(如果我们不能使用CDI的话)实际上具有真正单例的最简单方法(更重要的是也许是最安全的),例如使用如果过于天真地实现,则标准静态getInstance()方法模式仍然可以产生同一类的多个实例。同样,实现Serializable也可能导致产生多个实例,而Enum已经为我们处理了它,而没有意外的结果和样板。因此,文档也清楚地表明,Enum类型不仅仅是常量。因此,我想说的是,只要出于某些充分的理由而绝对需要在应用程序中拥有真正的单例,那么即使是可变的枚举也可能被视为合理使用。但是,在我看来,这个问题不可避免地趋于自以为是,并且不能完全公正地回答,因为有一些开发人员赞成不变性(而且我并不是说没有充分的理由),但还有开发人员在这方面没有那么严格的要求和基本文档技能的人有时可能和代码本身一样重要(这使我们无法突出枚举常量的内部状态实际上在javadoc中是可变的这一事实?)。

答案 7 :(得分:-3)

  

我想知道的是,是否有任何用例来创建可变的枚举?

枚举常量本身不可变,它们的字段是可变的。