[10] 枚举


1、枚举类的定义和意义

1.1 基本概念

枚举类型(Enumerated Type) 用来将一组类似的值包含到一种类型当中。而这种枚举类型的名称则会被定义成独一无二的类型描述符。

枚举类型的出现有什么意义?为什么不可以用普通的常量直接定义来替代呢?我们先看一个示例,假如现在希望为彩虹描述出七种颜色,在Java中通过常量定义的方式来实现:
 Public static class RainbowColor {  
    
    // 红橙黄绿青蓝紫七种颜色的常量定义
    public static final int RED = 0; 
    public static final int ORANGE = 1; 
    public static final int YELLOW = 2; 
    public static final int GREEN = 3; 
    public static final int CYAN = 4; 
    public static final int BLUE = 5; 
    public static final int PURPLE = 6; 
 }

然后在程序中,你可以直接引用这些常量。那么问题来了:
  • 类型不安全
  • 由于颜色常量的对应值是整数形,所以程序执行过程中很有可能给颜色变量传入一个任意的整数值,导致出现错误。

  • 没有命名空间
  • 由于颜色常量只是类的属性,当你使用的时候不得不通过类来访问。

  • 类型无指意性
  • 由于颜色常量值仅仅是一些无任何含义的整数值,如果在运行期调试时候,你就会发现日志中有很多魔术数字,但除了程序员本身,其他人很难明白其奥秘。

1.2 如何定义一个Enum类

如上提到的彩虹色,你用枚举类可以这样做:
enum RainbowColor { RED, ORANGE, YELLOW, GREEN, CYAN, BLUE, PURPLE }

创建枚举类型要使用 enum 关键字,它本质上是一个类,其隐含的父类是java.lang.Enum(java.lang.Enum 是一个抽象类)。所以自动继承了Enum的一些方法。

枚举类型符合通用模式 Class Enum<E extends Enum<E>>,而 E 表示枚举类型的名称。

枚举类型的每一个值都将映射到 protected Enum(String name, int ordinal) 构造函数中,在这里,每个值的名称都被转换成一个字符串,并且序数设置表示了此设置被创建的顺序

上面这些话的意思在于,假如有枚举类:
public enum Weekday {
    MON, TUE, WED, THU, FRI, SAT, SUN;
}

实际上这段代码调用了7次 Enum(String name, int ordinal):
new Enum<Weekday>("MON",0);
new Enum<Weekday>("TUE",1);
new Enum<Weekday>("WED",2);
...

取用的时候是这样:
Weekday wd = Weekday.MON;

枚举定义尽量以Enum结尾方便识别,如下的 WeekEnum
但枚举的基本使用,我们只能创建名称,例如星期,希望能有对应的值,怎么处理?枚举毕竟是一个类,所以完全可以这样:
// 定义一个星期的枚举类
public enum WeekEnum {

 // 因为已经定义了带参数的构造器,所以在列出枚举值时必须传入对应的参数
 SUNDAY("星期日"), MONDAY("星期一"), TUESDAY("星期二"), WEDNESDAY("星期三"), 
 THURSDAY("星期四"), FRIDAY("星期五"), SATURDAY("星期六");

 // 定义一个 private 修饰的实例变量
 private String value;

 // 定义一个带参数的构造器,枚举类的构造器只能使用 private 修饰
 private WeekEnum(String value) {
     this.value = value;
 }

 // 定义 get set 方法
 public String getValue() {
     return value;
 }

 public void setValue(String value) {
     this.value = value;
 }

}

1.3 Enum的好处

  • 枚举类(对象)可以直接用于switch语句(实际上的原理是,Java编译器会自动在枚举成员上调用ordinal()方法)
  • 作为类,它可以自定义属性和方法
  • 有EnumMap和EnumSet两个工具类,同时也是Map和Set接口的实现类,详见 Java 语言中 Enum 类型的使用介绍



2、如何避免错误地使用Enum

(1)enum 类型不支持 public 和 protected 修饰符的构造方法,因此构造函数一定要是 private 的。也正因为如此,所以枚举对象是无法在程序中通过直接调用其构造方法来初始化的。

(2)定义 enum 类型时候,如果是简单类型,那么最后一个枚举值后不用跟任何一个符号;但如果有定制方法,那么最后一个枚举值与后面代码要用分号';'隔开,不能用逗号或空格。

(3)由于 enum 类型的值实际上是通过运行期构造出对象来表示的,因而在做比较操作时候就需要注意,如果直接通过使用等号 ( ‘ == ’ ) 操作符,这些看似一样的枚举值一定不相等,因为这不是同一个对象实例。



3、枚举的常用方法

  • ordinal(),返回成员的声明顺序编号,初始为0,类似数组的索引
  • name(),返回枚举成员的名称
  • toString(),返回枚举常量的名称,和name()类似
  • values(),常用来遍历,返回枚举类的数组(values()是由编译器添加的static方法)



4、参考链接



posted @ 2017-09-01 10:06  Dulk  阅读(300)  评论(0编辑  收藏  举报