在Java中,你应该总是使用枚举而不是常量吗?

12
在 Java 1.5 及以前的版本中,常量将会被实现为如下方式:
public class MyClass {
    public static int VERTICAL = 0;
    public static int HORIZONTAL = 1;

    private int orientation;

    public MyClass(int orientation) {
        this.orientation = orientation;
    }
...

你可以像这样使用它:

MyClass myClass = new MyClass(MyClass.VERTICAL);

现在,在1.5版本中,显然应该使用枚举类型:

public class MyClass {
    public static enum Orientation {
        VERTICAL, HORIZONTAL;
    }

    private Orientation orientation;

    public MyClass(Orientation orientation) {
        this.orientation = orientation;
    }
...

现在您可以像这样使用它:

MyClass myClass = new MyClass(MyClass.Orientation.VERTICAL);

我觉得这有点丑陋。现在,我可以轻松地添加一对静态变量:

public class MyClass {
    public static Orientation VERTICAL = Orientation.VERTICAL;
    public static Orientation HORIZONTAL = Orientation.HORIZONTAL;

    public static enum Orientation {
        VERTICAL, HORIZONTAL;
    }

    private Orientation orientation;

    public MyClass(Orientation orientation) {
        this.orientation = orientation;
    }
...

现在我又可以这样做了:

MyClass myClass = new MyClass(MyClass.VERTICAL);

具备枚举类型安全的优点。

这是好的风格、坏的风格还是都不是?你能想到更好的解决方案吗?

更新

Vilx- 是第一个强调我感觉遗漏的部分——枚举应该是一等公民。在Java中,这意味着它在包中有自己的文件——我们没有命名空间。我曾认为这可能有些繁重,但实际上这样做肯定是正确的。

Yuval 的回答很好,但它没有真正强调非嵌套枚举。此外,对于1.4来说,在JDK中有很多地方使用整数,我真的在寻找一种使这种代码得以演变的方法。


在第一个代码块中,你是想给每个变量赋予不同的值,对吧? - Nate Parsons
你实际上需要 MyClass 类来做比不同的方向更多的事情吗? - Pål GD
7个回答

26

你把它复杂化了。我们把所有东西都整合在一起。

在Java 1.5之后,应该使用Java Enum类:

public enum Color
{
    BLACK, WHITE;
}

在Java 1.5版本之前,应该使用类型安全的枚举模式:

public class Color
{
    public static Color WHITE = new Color("white");
    public static Color BLACK = new Color("black");

    private String color;

    private Color(String s)
    {
        color = s;
    }
}

无论哪种方式,你都可以这样调用它:
drawBackground(Color.WHITE);

关于你的问题,这是一个代码风格的问题。但我认为最好的方式是把枚举类型放在它们自己的类中。特别是当它们开始拥有自己的方法,比如getName()getId()等等... 就像普通类与匿名类的困境一样,一旦类开始变得混乱,就是将其移到自己的文件中的时候了。


4
你知道你可以导入方向并说:
MyClass myClass = new MyClass(Orientation.VERTICAL);

?


好观点。是的,我这样做了,但这仍然意味着调用代码更冗长(它添加了一个导入行)。我的动机是保持调用代码更短、更清晰。 - Draemon
对不起,伙计。我的意思是,我喜欢Java和所有的东西,但在这种语言中,“更短”从来不是一个优先考虑的问题。 - Yoni Roit
3
更短?你是说...所以你宁愿一遍又一遍地写MyClass而不是一个导入语句?对我来说这既不更短也不更简洁。 - arul

1

有一类重要的情况,你应该使用常量而不是enum。这是当你想要使用常量进行算术运算或将它们与数值进行比较时。那么你真的需要这个东西是一个intlongdouble

相反,如果永远不会使用一个东西进行算术运算或数字比较,那么这个东西应该是一个对象而不是原始数字,因此enum更合适。


1

不知道Java怎么做,但在.NET中,良好的实践是将枚举与使用它们的类并列放置,即使它只被一个类使用。也就是说,你应该这样写:

namespace Whatever
{
    enum MyEnum
    {
    }
    class MyClass
    {
    }
}

因此,您可以使用:

MyClass c = new MyClass(MyEnum.MyValue);

0

在MyClass中,你也可以拥有两个静态方法:

MyClass.Vertical() : MyClass
MyClass.Horizontal() : MyClass

这些将返回一个具有正确枚举集的新实例。


0

我同意你很有创意,但我认为这不是一个实用的解决方案,而且我认为你只是把“丑陋”转移到了代码的另一部分。如果除了VERTICAL和HORIZONTAL之外,还有DIAGONAL、AA、BB、CC等,会发生什么?你要通过输入每个静态常量来复制吗?你对MyClass.Orientation.VERTICAL丑陋的品味可能是个人的?


我同意我刚刚转移了丑陋的代码,但我总是稍微更喜欢它在被调用的代码中而不是调用代码中。这完全是个人意见,我甚至不确定我是否喜欢替代方案,这就是为什么我正在寻求不同的观点。我得出的结论是最好使用一个单独的类。 - Draemon

-1

这取决于枚举可以拥有多少个值。在您的示例中,只有两个值,我会使用布尔类型。如果枚举只会被您编写的代码使用,并且不必与大量其他代码交互,那么也许您不需要类型安全。但是,如果它在“公共”方法中使用,我肯定会选择枚举,并将枚举放在自己的文件中。


你说得没错,但使用枚举比仅使用布尔值更能自我描述。 - Yoni Roit
但如果你只是将它传递到一个函数中,那么你可以将签名设置为“public MyClass(boolean isVertical)”。不过,这大概是我唯一会使用它的情况了。 - Nate Parsons

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接