美文网首页
[Java] enum 使用分析

[Java] enum 使用分析

作者: yyxyz2011 | 来源:发表于2016-06-05 11:30 被阅读849次

    背景

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

    相关文章

      网友评论

          本文标题:[Java] enum 使用分析

          本文链接:https://www.haomeiwen.com/subject/akcrdttx.html