[Java] enum 使用分析

背景

在 Java 语言中还没有引入枚举类型之前,表示枚举类型的常用模式是声明一组 int 常量。定义如下:

public class Color {
  public static final RED = 1;
  public static final GREEN = 2;
  public static final BLUE = 3;
}

这种模式通常称作 int 枚举模式。可是这种模式存在什么问题呢?通常我们写出来的代码都会从它的 ** 安全性 易用性可读性** 等方面来考虑。首先我们可以来考虑这种方式的类型安全性。比如我们设计一个函数,要求传入红、绿、蓝的某一个值。但是使用 int 类型,我们无法保证传入的值为合法。

public String getColor(int color) {
  String result = "";
  switch (color) {
    case Color.RED:
        result = "红色";
        break;
    case Color.GREEN:
        result = "绿色";
        break;
    case Color.BLUE:
        result = "蓝色";
        break;
    default:
        result = "未定义的颜色";
        break;
  }
  return result;
}

public void doSomething() {
  System.out.println( this.getColor(Color.RED)); //这是正常的使用场景
  System.out.println(this.getColor(5)); //这是不正常的使用场景,编译器不会报错,这就导致了类型不安全的问题
}

程序 getColor(Color.RED) 是我们预期的使用方法。可 getColor(5) 显然就不是了,而且编译可以通过,在运行时就会出现意想不到的情况。这显然就不符合 Java 程序的类型安全。

接下来我们来考虑一下这种模式的可读性。使用枚举的大多数场合,我都需要方便得到枚举类型的字符串表达式。如果将 int 枚举常量打印出来,我们所见到的就是一组数字,这是没什么太大的用处。我们可能会想到使 String 常量代替 int 常量。虽然它为这些常量提供了可打印的字符串,但是它会导致性能问题,因为它依赖于字符串的比较操作,所以这种模式也是我们不期望的。 所以有必要介绍一种新的方式:枚举类型。

定义

枚举类型是指由一组固定的常量组成合法的类型,由 enum 关键字来定义一个枚举类型。下面就是 Java 枚举类型的定义:

public enum Color {  
    RED, GREEN, BLUE
}  

特点

  1. 使用关键字 enum
  1. 类型名称
  2. 一串值
  3. 可以定义在单独的文件中,也可以嵌在 Java 文件中
  4. 可以实现一个或多个接口,
  5. 可以定义新的变量
  6. 可以定义新的方法
  7. 可以定义根据具体值而相异的类

从上面的特点中可以看出 Java 中的枚举类型很像一个特殊的 class, 实际上 enum 声明确实定义的就是一个类。这些类继承自类库 (java.lang.Enum<E>)。通过对上面的 Color 反编译后我们可以发现这一事实:

// 被编译器加上final声明,故该类是无法继承的
public final class Color extends Enum
{
    
    public static Color[] values()
    {
        return (Color[])$VALUES.clone();
    }
    // 实现 Enum 中的抽象方法
    public static Color valueOf(String s)
    {
        return (Color)Enum.valueOf(Color, s);
    }
    // 私有构造器,外部不能动态创建一个枚举对象
    private Color(String s, int i)
    {
        super(s, i);
    }

    //所有的枚举值都是静态常量
    public static final Color RED;
    public static final Color GREEN;
    public static final Color BLUE;
    private static final Color $VALUES[];

    // 对枚举类的所有枚举值对象进行第一次初始化
    static 
    {
        RED = new Color("RED", 0);
        GREEN = new Color("GREEN", 1);
        BLUE = new Color("BLUE", 2);
        $VALUES = (new Color[] {
            RED, GREEN, BLUE
        });
    }
}

使用方法

1、Color 枚举类就是 class,而且是一个不可以被继承的 final 类。其枚举值(RED, Green, BLUE) 都是 Color 类型的类静态常量, 所以我们可以通过下面的方式来得到 Color 枚举类的一个实例:

Color c=Color.RED; 

2、即然枚举类是 class,当然在枚举类型中有构造器,方法和数据域。但是,枚举类的构造器有很大的不同:

  • (1) 构造器只能在构造枚举值的时候被调用。
  • (2) 构造器只能私有 private,绝对不允许有 public 构造器。 这样可以保证外部代码无法新构造枚举类的实例。这也是完全符合情理的,因为我们知道枚举值是 public static final 的常量而已。 但枚举类的方法和数据域可以允许外部访问。

3、所有枚举类都继承了 Enum 的方法,下面我们详细介绍这些方法。

  • (1) ordinal() 方法: 返回枚举值在枚举类中的顺序。这个顺序根据枚举值声明的顺序而定。
Color.RED.ordinal();  //返回结果:0        
Color.BLUE.ordinal();  //返回结果:1   ```   

* (2)  `compareTo()`方法: `Enum` 实现了 `java.lang.Comparable` 接口,因此可以比较对象的顺序。`Enum` 中的 `compareTo` 返回的是两个枚举值的顺序之差。当然,前提是两个枚举值必须属于同一个枚举类,否则会抛出 `ClassCastException()` 异常。          
    

Color.RED.compareTo(Color.BLUE); //返回结果 -1


 * (3)  `values()` 方法: 静态方法,返回一个包含全部枚举值的数组。            
    

Color[] colors=Color.values();
for(Color c:colors {
System.out.print(c+",");
} //返回结果:RED, GREEN, BLUE


 * (4)  `toString()` 方法: 返回枚举常量的名称。   

Color c = Color.RED;
System.out.println(c); //返回结果: RED


* (5)  `valueOf()` 方法: 这个方法和`toString` 方法是相对应的,返回带指定名称的指定枚举类型的枚举常量。

Color.valueOf("BLUE"); //返回结果: Color.BLUE


 * (6)  `equals()` 方法: 比较两个枚举类对象的引用。


## 总结

那么什么时候应该使用枚举呢?每当需要一组固定的常量的时候,如一周的天数、一年四季等。或者是在我们编译前就知道其包含的所有值的集合。Java 1.5的枚举能满足绝大部分程序员的要求的,它的简明,易用的特点是很突出的。
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,542评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,596评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 158,021评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,682评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,792评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,985评论 1 291
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,107评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,845评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,299评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,612评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,747评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,441评论 4 333
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,072评论 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,828评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,069评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,545评论 2 362
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,658评论 2 350

推荐阅读更多精彩内容