一个JDK1.5的新特性:枚举学习笔记

来源:互联网 发布:压力容器设计 知乎 编辑:程序博客网 时间:2024/05/21 06:29

枚举

枚举就是一个特殊的类。可以有若干公有方法或抽象方法。采用抽象方法定义nextDay就将大量的if.else语句转移成了一个个独立的类。

枚举的构造方法等其他信息必须放在成员类表之后,而且枚举的构造方法必须是私有的。

有多个构造方法时,枚举元素后面跟上一对大括号就表示构造枚举元素指向的是哪个构造方法。有带参数的构造方法,还有不带参数的构造方法。

枚举元素MON和MON()的效果一样,都是调用默认的构造方法。

 枚举只有一个成员时,就可以作为一种单例的实现方式。


为什么要用枚举?

曾经看到过一篇文章,觉得讲得很好,先拿来分享给大家:

Java中为什么引入枚举及引入枚举的好处

在实际编程中,往往存在着这样的“数据集”,它们的数值在程序中是稳定的,而且“数据集”中的元素是有限的。例如星期一到星期日七个数据元素组成了一周的“数据集”,春夏秋冬四个数据元素组成了四季的“数据集”。在Java中想表示这种数据集最容易想到的写法可能是这样,我们以表示一周五天的工作日来举例:

Java代码:

[java] view plaincopy
  1. publicclass WeekDay {  
  2.        public static final int MONDAY = 1;  
  3.        public static final int TUESDAY = 2;  
  4.        public static final int WENSDAY = 3;  
  5.        public static final int THURSDAY = 4;  
  6.        public static final int FRIDAY = 5;  
  7. }  


       现在,你的类就可以使用像WeekDay.TUESDAY这样的常量了。但是这里隐藏着一些问题,这些常量是Java中int类型的常量,这意味着该方法可以接受任何int 类型的值,即使它和WeekDay中定义的所有日期都对应不上。因此,您需要检测上界和下界,在出现无效值的时候,可能还要抛出一个

IllegalArgumentException。而且,如果后来又添加另外一个日期(例如

WeekDay.SATURDAY ),那么必须改变所有代码中的上界,才能接受这个新值。 换句话说,在使用这类带有整型常量的类时,这个方案也许可行,但并不是非常有效。

Joshua Bloch老大这时站了出来,在他的著作《Effective Java》中提出了在这样场景下的一种非常好的模式——Type-safe enumeration pattern。这个模式简而言之就是给这样的常量类一个私有的构造方法,然后声明一些public static final的同类型的变量暴露给使用者,例如:

Java代码

      

[java] view plaincopy
  1.  public class WeekDay {  
  2.         publicstatic final WeekDay MONDAY = new WeekDay(1);  
  3.         publicstatic final WeekDay TUESDAY = new WeekDay(2);    
  4.         publicstatic final WeekDay WENSDAY = new WeekDay(3);  
  5.        public static final WeekDay THURSDAY =new WeekDay(4);  
  6.         publicstatic final WeekDay FRIDAY = new WeekDay(5);  
  7.         publicint getValue(){  
  8.            returnvalue;  
  9.         }  
  10.         privateint value;  
  11.         privateWeekDay(int i){  
  12.            this.value= i;  
  13.         }  
  14.         //othermethods...  
  15. }  

       这样做的好处是你的程序现在接受的不是int类型的数据了,而是WeekDay的一个预定义好的staticfinal的实例(WeekDay.TUESDAY等),例如:

Java代码

       public void setWeekDay(WeekDay weekDay){...}

       而这样做也避免了可以随意向方法中传递一个不合法的int型数值(例如-1)而造成程序错误。同时,它还会带来其他的一些好处:由于这些枚举的对象都是一些类的实例,所以在里面放一些需要的属性来存放数据;又由于他们都是单例的,你可以使用equals方法或是==符号来比较它们。Perfect!


前面说了Joshua Bloch大大提出的枚举模式,很好用但是好麻烦啊。如果你用过C/C++或是Pascal这样的语言的话一定会对它们的枚举类型有印象,例如在C/C++中我们可以这样定义:

Cpp代码:

 

[cpp] view plaincopy
  1. enum weekday {  
  2.      MONDAY,  
  3.      TUESDAY,  
  4.      WENSDAY,  
  5.      THURSDAY,  
  6.      FRIDAY  
  7.  };  

       然后在程序中就可以用MONDAY、TUESDAY这些变量了。这样多方便,但是Java1.4以前的版本并没有提供枚举类型的支持,所以如果你是用JDK 1.4开发程序的话就只能像JoshuaBloch老大那样写了。从Java 5.0(代号为Tiger)开始,这种情况改变了,Java从语言层面支持了枚举类型。

       枚举是Tiger的一个很重要的新特性,它是一种新的类型,允许用常量来表示特定的数据片断,而且全部都以类型安全的形式来表示,它使用“enum”关键字来定义。

我们先来写一个简单的枚举类型的定义:

Java代码:

      

[java] view plaincopy
  1. public enum WeekDay{  
  2.        MONDAY,TUESDAY, WENSDAY, THURSDAY, FRIDAY;  
  3.    //最后这个“;”可写可不写。  
  4.    }  

      

       这和类、接口的定义很相像嘛!Tiger中的枚举类型就是一种使用特殊语法“enum”定义的类。所有的枚举类型是java.lang.Enum的子类。这是Tiger中新引入的一个类,它本身并不是枚举类型,但它定义了所有枚举类型所共有的行为,如下表:


注意:虽然所有的枚举类型都继承自java.lang.Enum,但是你不能绕过关键字“enum”而使用直接继承Enum的方式来定义枚举类型。编译器会提示错误来阻止你这么做。

       WeekDay中定义的五个枚举常量之间使用“,”分割开来。这些常量默认都是“public static final”的,所以你就不必再为它们加上“public static final”修饰(编译器会提示出错),这也是为什么枚举常量采用大写字母来命名的原因。而且每一个常量都是枚举类型WeekDay的一个实例。你可以通过类似“WeekDay.MONDAY”这种格式来获取到WeekDay中定义的枚举常量,也可以采用类似“WeekDay oneDay = WeekDay.MONDAY”的方式为枚举类型变量赋值(你不能给枚举类型变量分配除了枚举常量和null以外的值,编译器会提示出错)。

       作为枚举类型实例的枚举常量是如何初始化的呢?其实答案很简单,这些枚举常量都是通过Enum中定义的构造函数进行初始化的。

Java代码:

      

[java] view plaincopy
  1. //java.lang.Enum中定义的构造函数,  
  2.    //两个参数分别是定义的枚举常量名称以及它所在的次序。  
  3.    protected Enum(String name, int ordinal) {  
  4.        this.name= name;  
  5.        this.ordinal= ordinal;  
  6.    }  

       在初始化的过程中,枚举常量的次序是按照声明的顺序安排的。第一个枚举常量的次序是0,依此累加。

       枚举类型除了拥有Enum提供的方法以外,还存在着两个隐藏着的与具体枚举类型相关的静态方法——values()和valueOf(String arg0)。方法values()可以获得包含所有枚举常量的数组;方法valueOf是java.lang.Enum中方法valueOf的简化版本,你可以通过它,根据传递的名称来得到当前枚举类型中匹配的枚举常量。
0 0
原创粉丝点击