Java 枚举
1. 枚举的概念¶
enum 的全称为 enumeration, 是 JDK 1.5 中引入的新特性。在Java中,被 enum关键字修饰的类型就是枚举类型。形式如下:
enum Color { RED, GREEN, BLUE }
如果枚举不添加任何方法,枚举值默认为从0开始的有序数值。以 Color 枚举类型举例,它的枚举常量依次为 RED:0,GREEN:1,BLUE:2。
枚举的好处:可以将常量组织起来,统一进行管理。
枚举的典型应用场景:错误码、状态机等。
2. 枚举的本质¶
枚举类型的本质,尽管 enum 看起来像是一种新的数据类型,事实上,enum是一种受限制的类,并且具有自己的方法。
创建enum时,编译器会为你生成一个相关的类,这个类继承自 java.lang.Enum
。
java.lang.Enum类声明
public abstract class Enum<E extends Enum<E>> implements Comparable<E>, Serializable { ... }
3. 枚举的方法¶
在enum中,提供了一些基本方法:
方法 | 说明 |
---|---|
values() | 返回 enum 实例的数组,而且该数组中的元素严格保持在 enum 中声明时的顺序 |
name() | 返回实例名。 |
ordinal() | 返回实例声明时的次序,从0开始 |
getDeclaringClass() | 返回实例所属的 enum 类型 |
equals() | 判断是否为同一个对象。 |
可以使用 == 来比较enum实例。此外,java.lang.Enum实现了Comparable和 Serializable 接口,所以也提供 compareTo() 方法
demo
package edemo; /** * @author summer * @create 2020-02-06 11:45 */ public class em1 { enum Color {RED, GREEN,BLUE}; enum Size {BIG, MIDDLE, SMALL;} public static void main(String args[]) { System.out.println("----------"); for (Color c : Color.values()) { System.out.println(c + " ordinal: " + c.ordinal()); } System.out.println("----------"); for (Size s : Size.values()) { System.out.println(s + " ordinal: " + s.ordinal()); } Color green = Color.GREEN; System.out.println("green name(): " + green.name()); System.out.println("green getDeclaringClass(): " + green.getDeclaringClass()); System.out.println("green hashCode(): " + green.hashCode()); System.out.println("green compareTo Color.GREEN: " + green.compareTo(Color.GREEN)); System.out.println("green equals Color.GREEN: " + green.equals(Color.GREEN)); System.out.println("green equals Size.MIDDLE: " + green.equals(Size.MIDDLE)); System.out.println("green equals 1: " + green.equals(1)); System.out.format("green == Color.BLUE: %b\n", green == Color.BLUE); } }
输出结果
---------- RED ordinal: 0 GREEN ordinal: 1 BLUE ordinal: 2 ---------- BIG ordinal: 0 MIDDLE ordinal: 1 SMALL ordinal: 2 green name(): GREEN green getDeclaringClass(): class edemo.em1$Color green hashCode(): 214126413 green compareTo Color.GREEN: 0 green equals Color.GREEN: true green equals Size.MIDDLE: false green equals 1: false green == Color.BLUE: false
除了不能继承,基本上可以将 enum 看做一个常规的类。
2. 枚举不可以继承¶
enum 不可以继承另外一个类,当然,也不能继承另一个 enum 。因为 enum 实际上都继承自 java.lang.Enum 类,而 Java 不支持多重继承,所以 enum 不能再继承其他类,当然也不能继承另一个 enum
3. 枚举方法¶
在概念章节提到了,枚举值默认为从0开始的有序数值 。那么问题来了:如何为枚举显示的赋值。
Java 不允许使用 = 为枚举常量赋值
如果你接触过C/C++
,你肯定会很自然的想到赋值符号 =
。在C/C++语言中的enum,可以用赋值符号=显示的为枚举常量赋值;但是 ,很遗憾,Java 语法中却不允许使用赋值符号 = 为枚举常量赋值。
例:C/C++ 语言中的枚举声明
typedef enum{ ONE = 1, TWO, THREE = 3, TEN = 10 } Number;
枚举可以添加普通方法、静态方法、抽象方法、构造方法,Java虽然不能直接为实例赋值,但是它有更优秀的解决方案:为enum添加方法来间接实现显示赋值。创建enum时,可以为其添加多种方法,甚至可以为其添加构造方法。
注意一个细节:如果要为enum定义方法,那么必须在enum的最后一个实例尾部添加一个分号。此外,在enum中,必须先定义实例,不能将字段或方法定义在实例前面。否则,编译器会报错。
全面展示如何在枚举中定义普通方法、静态方法、抽象方法、构造方法
package edemo; /** * @author summer * @create 2020-02-06 12:18 */ public enum ErrorCode { OK(0) { public String getDescription() { return "成功"; } }, ERROR_A(100) { public String getDescription() { return "错误A"; } }, ERROR_B(200) { public String getDescription() { return "错误B"; } }; private int code; // 构造方法:enum的构造方法只能被声明为private权限或不声明权限 private ErrorCode(int number) { // 构造方法 this.code = number; } public int getCode() { // 普通方法 return code; } // 普通方法 public abstract String getDescription(); // 抽象方法 public static void main(String args[]) { // 静态方法 for (ErrorCode s : ErrorCode.values()) { System.out.println("code: " + s.getCode() + ", description: " + s.getDescription()); } } }
运行结果
code: 0, description: 成功 code: 100, description: 错误A code: 200, description: 错误B
注:上面的例子并不可取,仅仅是为了展示枚举支持定义各种方法。
下面是一个简化的例子,一个错误码枚举类型的定义
demo
package edemo; /** * @author summer * @create 2020-02-06 12:18 */ public enum ErrorCodeEn { OK(0, "成功"), ERROR_A(100, "错误A"), ERROR_B(200, "错误B"); ErrorCodeEn(int number, String description) { this.code = number; this.description = description; } private int code; private String description; public int getCode() { return code; } public String getDescription() { return description; } public static void main(String args[]) { // 静态方法 for (ErrorCodeEn s : ErrorCodeEn.values()) { System.out.println("code: " + s.getCode() + ", description: " + s.getDescription()); } } }
运行结果
code: 0, description: 成功 code: 100, description: 错误A code: 200, description: 错误B
4. 枚举的应用场景¶
组织常量
在JDK1.5 之前,在Java中定义常量都是public static final TYPE a
;这样的形式。有了枚举,你可以将有关联关系的常量组织起来,使代码更加易读、安全,并且还可以使用枚举提供的方法。
枚举声明的格式
下面三种声明方式是等价的:
enum Color { RED, GREEN, BLUE } enum Color { RED, GREEN, BLUE, } enum Color { RED, GREEN, BLUE; }
注:如果枚举中没有定义方法,也可以在最后一个实例后面加逗号、分号或什么都不加。
switch 状态机
我们经常使用switch语句来写状态机。JDK7以后,switch已经支持int、char、String、enum类型的参数。这几种类型的参数比较起来,使用枚举的switch代码更具有可读性。
状态机
public class em1 { public static void main(String args[]) { System.out.println(getTrafficInstruct(Signal.GREEN)); } enum Signal {RED, YELLOW, GREEN} public static String getTrafficInstruct(Signal signal) { String instruct = "信号灯故障"; switch (signal) { case RED: instruct = "红灯停"; break; case YELLOW: instruct = "黄灯请注意"; break; case GREEN: instruct = "绿灯行"; break; default: break; } return instruct; } }
运行结果
绿灯行