[Java] enum 使用分析

2016-06-05  本文已影响849人  yyxyz2011

背景

在 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,当然在枚举类型中有构造器,方法和数据域。但是,枚举类的构造器有很大的不同:

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

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的枚举能满足绝大部分程序员的要求的,它的简明,易用的特点是很突出的。
上一篇下一篇

猜你喜欢

热点阅读