Understanding Enums in Java
什么是Java枚举?它们是如何工作的?我可以在哪里使用它们?如何使用?我可以不在应用程序中使用枚举吗?或者它们的功能强大到使用它们比忽略它们更好吗?
Java 5中的Enums基本上是具有预定义的实例集的类。它们是用来替换整数常量集合的。它们最好是常量,因为它们可以加强类型安全性。
因此,而不是:
1 2 3 4 5 6 | public class Suit { public final static int SPADES = 1; public final static int CLUBS = 2 public final static int HEARTS = 3; public final static int DIAMONDS = 4; } |
你有:
1 2 3 | public enum Suit { SPADES, CLUBS, HEARTS, DIAMONDS } |
其优点是:
类型安全性是一个问题,因为在第一个示例中,这些是有效的语句:
1 | int i = Suit.DIAMONDS * Suit.CLUBS; |
或者,您可以将11传递给一个需要西装的函数。不能使用类型安全枚举执行此操作。
您可以使用一个类来提供类型安全性,这是Java 5之前的解决方案。Josh Bloch(在JavaJava中,它是Java程序员IMRO必须阅读的),它促进了成为Java 5 +枚举的Type SeaFe枚举模式。它上面有大量的样板文件,还有一些人们不喜欢处理的角落案例,例如序列化而不是调用构造函数,为了确保只有一个实例,您必须重写readresolve()方法。
例如:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | public enum CardColour { RED, BLACK } public enum Suit { SPADES(CardColour.BLACK), CLUBS(CardColour.BLACK), HEARTS(CardColour.RED), DIAMONDS(CardColour.RED); private final CardColour colour; Suit(CardColour colour) { this.colour = colour; } public CardColour getColour() { return colour; } } |
编辑:Sun介绍了类型安全枚举。
至于接口,它们实际上是对枚举的补充,而不是作为可选的。就像你可以说西服是一个界面,你可以这样说:
1 2 3 | public interface Suit { CardColour getColour(); } |
问题是你可以去定义300种不同的西装,你也可以定义几次黑桃。枚举的另一个优点是(尽管有类装入角的情况),每个枚举值只有一个实例。通常,这被称为具有规范值,这意味着该等同性为真:
1 | a.equals(b) == b.equals(a) == (a == b) |
对于所有是特定枚举实例的A、B。这意味着,与其写:
1 | if (card.getSuit().equals(Suit.SPADES)) { ... } |
你可以写:
1 | if (card.getSuit() == Suit.SPADES) { ... } |
它更快,而且通常更容易阅读。另外,如果您比较不同类型的枚举说它们不可能相等,IDES通常会给您反馈,这是一种有用的早期错误检查形式。
把枚举想象成如下
1 2 3 4 5 6 7 8 9 10 11 12 13 | public class MyEnum { // Object instantiated at declaration public static final MyEnum ONE = new MyEnum(); public static final MyEnum TWO = new MyEnum(); public static final MyEnum THREE = new MyEnum(); // Notice a private constructor // There is no way outside MyEnum class call it private MyEnum() { ... } } |
所以作为枚举的myenum
1 2 3 4 5 | public enum MyEnum { ONE, TWO, THREE; } |
两者都相似
当做,
为了添加一些额外的信息来进一步了解它,最好从变量及其值的概念开始。现在我确信,每个变量都有一个声明类型(例如Java基元类型)。每种类型都有自己的对应值。例如,char类型的变量可以接受所有单个字符作为其值。因此,当您想要声明一个变量可以接受所有字符常量集时,这是非常有用的。例如,所有字符常量都是可接受的,并且对于一个cartostopoprogram变量是有意义的:
1 | char aCharToStopProgram = getUserInput(); |
但是,当你有一个有限的值时,我的意思是变量的值域被限制为特殊的值。例如,您有保留系统多项选择问题值的用户选择。所以"a"、"b"、"c"、"d"才有意义。您不希望在程序代码的其他部分(或任何其他原因)为该变量分配无意义的值,如"s"。现在,对我们的变量使用char原语类型是正确的,它可以接受任何字符常量,比如下面的。
1 | char userChoice = getUserChoice(); |
在这种情况下,Java提供枚举类型。这意味着,通过枚举关键字,您可以定义一个新类,该类具有有限和固定的实例,这些实例称为命名值(不能创建新对象)。例如:
1 | enum MultipleChoiceAnswer { A, B, C, D }; |
或
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | public enum MultipleChoiceAnswer { A('a'), B('b'), C('c'), D('d'); private char choice; private MultipleChoiceAnswer(char choice) { this.choice = choice; } public String getChoice() { return choice; } } |
因此,您可以使用自己的类型定义变量:
1 | MultipleChoiceAnswer userChoice = getUserChoice();//OR MultipleChoiceAnswer.A |
如果情况不好,你就不需要他们了。
它们允许你有一套定义明确的事物,例如,如果你想代表物质的状态,你可以:
1 2 3 4 5 | enum MatterState { Solid, Liquid, Gas; } |
它们以多种方式击败了使用对象表示集的旧风格,其中一些方式是:
- 你可以在开关中使用它们声明。
- 更少的代码。
- 内置的到/来自字符串。
Sun的枚举文档可能是最好的解释。当然,在Java 1.5发布之前,Java程序员当然可以不用它们。通常在1.5之前使用Java版本中的常量来完成同样的事情。但枚举是一种很好的方便。
从我的解释来看,枚举比其他任何东西都更易于阅读。它们基本上用于用更多描述性的名称替换1-6这样的值,例如[高兴、悲伤、愤怒等]当需要使用一组小变量来描述您期望的解决方案时,应该使用它们。