Java 枚举类详解
1. 枚举类定义
在某些情况下,一个类的对象是有限而且固定的,比如季节类,它只有4个对象,这种实例有限而且固定的类,在java里被称为枚举类。
2. 早期实现枚举的方式
public static final int season_spring = 1; public static final int season_summer= 2; public static final int season_fall = 3; public static final int season_winter = 4;
这种定义季节的方式简单明了,但存在如下几个问题:
1)类型不安全:因为上面的每个季节实际上是一个int整数,因此完全可以把一个季节当成一个int整数使用,例如进行加法运算season_spring+season_summer,这种代码完全正常。
2)没有命名空间:当需要使用季节时,必须在spring前使用season_前缀,否则程序可能与其它类中的静态常量混淆。
3)打印输出的意义不明确:当输出某个季节时,例如输出season_spring,实际上输出的是1,这个1很难猜测出它是代表春天的。
但枚举又确实存在的意义,因此早期也可采用通过定义类的方式来实现,可以采用如下设计方式。
1)通过private将构造器隐藏起来。
2)把这个类的所有可能实例都使用public static final修饰的类变量来保存。
3)如果有必要,可以提供一些静态方法,允许其他程序根据特定参数来获取与之匹配的实例。
4)使用枚举类可以使程序更加健壮,避免创建对象的随意性。
但通过定义类来实现枚举的代码量比较大,实现起来比较麻烦,java从jdk1.5后就增加了对枚举类的支持。
3. 枚举类详解
java5新增了一个enum关键字(它与class、interface关键字的地位相同),用以定义枚举类。正如前面看到的,枚举类是一个特殊的类,它一样可以有自己的成员变量、方法,可以实现一个或者多个接口,也可以定义自己的构造器。一个java源文件中最多只能定义一个public访问权限的枚举类,且该java源文件也必须和该枚举类的类名相同。
但枚举类终究不是普通的类,它与普通类有如下区别:
1)枚举类不能显示继承其它类,枚举类可以实现一个或多个接口,使用enum定义的枚举类默认继承了java.lang.enum类,而不是默认继承object类。其中enum类实现了serializable和comparable两个接口。
2)枚举类不能派生子类,使用enum定义、非抽象的枚举类默认会使用final修饰。
3)枚举类的构造器只能使用private访问控制符,如果省略了构造器的访问控制符,则默认使用private修饰。
4)枚举类的实例必须在枚举类的第一行显示列出,否则这个枚举类永远都不能产生实例。列出这些实例时,系统会自动添加public static final修饰,无需程序员显示添加。
枚举类默认提供了一个values()方法,该方法可以很方便的遍历所有枚举值。
下面程序定义了一个seasonenum枚举类
public enum seaonenum{ //在第一行列出4个枚举实例 spring,summer,fall,winter; }
定义枚举类时必须显示的列出所有的枚举值,枚举值之间使用英文逗号隔开,以英文分号结束。
如果需要使用该枚举类的某个实例,则可以使用类名.变量名的形式,如seaonenum.spring。
看下面程序实例:
public class enumtest{ public void judge(seasonenum s) //switch语句里的表达式可以是枚举值 switch(s){ case spring: system.out.println("春暖花开,正好踏青"); break; case summer: system.out.println("夏日炎炎,适合游泳"); break; case fall: system.out.println("秋高气爽,及时进补"); break; case winter: system.out.println("冬日飘雪,围炉赏雪"); break; } } public static void main(string[] args){ //枚举类默认有一个values()方法,返回该枚举类的所有实例 for(seasonenum s : seasonenum.values()){ system.out.println(s); } //使用枚举实例时,可通过enumclass.variable形式来访问 new enumtest().judge(seasonenum.spring); }
}
上面程序测试了seasonenum枚举类的用法,该类通过values()方法返回了seasonenum枚举类的所有实例,并通过循环迭代输出了seasonenum枚举类的所有实例。
由于所有的枚举类都继承了java.lang.enum类,所以枚举类可以直接使用java.lang.enum类中所包含的方法。java.lang.enum类中提供了如下几个方法。
1)int compareto(e o):比较此枚举与指定对象的顺序。在该对象小于、等于或大于指定对象时,分别返回负整数、零或正整数。 枚举常量只能与相同枚举类型的其他枚举常量进行比较。该方法实现的自然顺序就是声明常量的顺序。
2)string name():返回此枚举常量的名称,在其枚举声明中对其进行声明。 与此方法相比,大多数程序员应该优先考虑使用tostring()方法,因为 tostring 方法返回更加用户友好的名称。该方法主要设计用于特殊情形,其正确性取决于获取正确的名称,其名称不会随版本的改变而改变。
3) int ordinal():返回枚举常量的序数(它在枚举声明中的位置,其中初始常量序数为零)。 大多数程序员不会使用此方法。它被设计用于复杂的基于枚举的数据结构,比如 enumset
和 enummap
。
4)string tostring():返回枚举常量的名称,它包含在声明中。可以重写此方法,虽然一般来说没有必要。当存在更加“程序员友好的”字符串形式时,应该使用枚举类型重写此方法。
5)public static <t extends enum<t>> t valueof(class<t> enumtype,string name):返回带指定名称的指定枚举类型的枚举常量。名称必须与在此类型中声明枚举常量所用的标识符完全匹配。(不允许使用额外的空白字符。)
正如前面看到的,当程序使用system.out.println(s)语句来打印枚举值时,实际上输出的是该枚举值得tostring()方法,也就是输出该枚举值的名字。
欢迎关注微信公众号【java典籍】,收看更多java技术干货!
▼微信扫一扫下图↓↓↓二维码关注