java?枚举类型enum?的使用
最近跟同事讨论问题的时候,突然同事提到我们为什么java?中定义的常量值不采用enmu?枚举类型,而采用public final static?类型来定义呢?以前我们都是采用这种方式定义的,很少采用enum?定义,所以也都没有注意过,面对突入起来的问题,还真有点不太清楚为什么有这样的定义。既然不明白就抽时间研究下吧。
Java?中的枚举类型采用关键字enum?来定义,从jdk1.5才有的新类型,所有的枚举类型都是继承自Enum?类型。要了解枚举类型,建议大家先打开jdk?中的Enum?类简单读一下,这个类里面定义了很多protected?方法,比如构造函数,如果要使用这些方法我们可以把枚举类型定义到当前类中。每个枚举类型,都有自己的名字和顺序,当我们输出一个枚举类型的时候,会输入枚举类型的name?,具体可以参考下面的例子。
一、???通常定义常量方法
我们通常利用public final static?方法定义的代码如下,分别用1?表示红灯,3?表示绿灯,2?表示黄灯。
?
package?com.csdn.myEnum; public?class?Light { ????/*?红灯?*/ ????public?final?static?int?RED?=1; ????/*?绿灯?*/ ????public?final?static?int?GREEN?=3; ????/*?黄灯?*/ ????public?final?static?int?YELLOW?=2; } |
?
?
二、???枚举类型定义常量方法
枚举类型的简单定义方法如下,我们似乎没办法定义每个枚举类型的值。比如我们定义红灯、绿灯和黄灯的代码可能如下:
?
public?enum?Light { ???????RED?,?GREEN?,?YELLOW?; } |
?
我们只能够表示出红灯、绿灯和黄灯,但是具体的值我们没办法表示出来。别急,既然枚举类型提供了构造函数,我们可以通过构造函数和覆写toString?方法来实现。首先给Light?枚举类型增加构造方法,然后每个枚举类型的值通过构造函数传入对应的参数,同时覆写toString?方法,在该方法中返回从构造函数中传入的参数,改造后的代码如下:
?
public?enum?Light { ???????//?利用构造函数传参 ???????RED?(1),?GREEN?(3),?YELLOW?(2); ? ???????//?定义私有变量 ???????private?int?nCode?; ? ???????//?构造函数,枚举类型只能为私有 ???????private?Light(?int?_nCode) { ???????????this?.?nCode?= _nCode; ???????} ? ???????@Override ???????public?String toString() { ???????????return?String.valueOf?(?this?.?nCode?); ???????} ????} |
?
?
三、???完整示例代码
枚举类型的完整演示代码如下:
?
package?com.csdn.myEnum; ? import?java.util.EnumMap; import?java.util.EnumSet; ? public?class?LightTest { ? ????// 1.?定义枚举类型 ????public?enum?Light { ???????//?利用构造函数传参 ???????RED?(1),?GREEN?(3),?YELLOW?(2); ? ???????//?定义私有变量 ???????private?int?nCode?; ? ???????//?构造函数,枚举类型只能为私有 ???????private?Light(?int?_nCode) { ???????????this?.?nCode?= _nCode; ???????} ? ???????@Override ???????public?String toString() { ???????????return?String.valueOf?(?this?.?nCode?); ???????} ????} ? ????/** ??????*?@param?args ??????*/ ????public?static?void?main(String[]?args?) { ? ???????// 1.?遍历枚举类型 ???????System.?out?.println(?"?演示枚举类型的遍历?......"?); ???????testTraversalEnum?(); ? ???????// 2.?演示?EnumMap?对象的使用 ???????System.?out?.println(?"?演示?EnmuMap?对象的使用和遍历?....."?); ???????testEnumMap?(); ? ???????// 3.?演示?EnmuSet?的使用 ???????System.?out?.println(?"?演示?EnmuSet?对象的使用和遍历?....."?); ???????testEnumSet?(); ????} ? ????/** ??????*?演示枚举类型的遍历 ??????*/ ????private?static?void?testTraversalEnum() { ???????Light[] allLight = Light.values?(); ???????for?(Light aLight : allLight) { ???????????System.?out?.println(?"?当前灯?name?:?"?+ aLight.name()); ???????????System.?out?.println(?"?当前灯?ordinal?:?"?+ aLight.ordinal()); ???????????System.?out?.println(?"?当前灯:?"?+ aLight); ???????} ????} ? ????/** ??????*?演示?EnumMap?的使用,?EnumMap?跟?HashMap?的使用差不多,只不过?key?要是枚举类型 ??????*/ ????private?static?void?testEnumMap() { ???????// 1.?演示定义?EnumMap?对象,?EnumMap?对象的构造函数需要参数传入?,?默认是key?的类的类型 ???????EnumMap<Light, String> currEnumMap =?new?EnumMap<Light, String>( ??????????????Light.?class?); ???????currEnumMap.put(Light.?RED?,?"?红灯?"?); ???????currEnumMap.put(Light.?GREEN?,?"?绿灯?"?); ???????currEnumMap.put(Light.?YELLOW?,?"?黄灯?"?); ? ???????// 2.?遍历对象 ???????for?(Light aLight : Light.values?()) { ???????????System.?out?.println(?"[key="?+ aLight.name() +?",value=" ??????????????????+ currEnumMap.get(aLight) +?"]"?); ???????} ????} ? ????/** ??????*?演示?EnumSet?如何使用,?EnumSet?是一个抽象类,获取一个类型的枚举类型内容<BR/> ??????*?可以使用?allOf?方法 ??????*/ ????private?static?void?testEnumSet() { ???????EnumSet<Light> currEnumSet = EnumSet.allOf?(Light.?class?); ???????for?(Light aLightSetElement : currEnumSet) { ???????????System.?out?.println(?"?当前?EnumSet?中数据为:?"?+ aLightSetElement); ???????} ? ????} } ? |
?
?
执行结果如下:
?
演示枚举类型的遍历?...... 当前灯?name?:?RED 当前灯?ordinal?:?0 当前灯:?1 当前灯?name?:?GREEN 当前灯?ordinal?:?1 当前灯:?3 当前灯?name?:?YELLOW 当前灯?ordinal?:?2 当前灯:?2 演示?EnmuMap?对象的使用和遍历?..... [key=RED,value=?红灯?] [key=GREEN,value=?绿灯?] [key=YELLOW,value=?黄灯?] 演示?EnmuSet?对象的使用和遍历?..... 当前?EnumSet?中数据为:?1 当前?EnumSet?中数据为:?3 当前?EnumSet?中数据为:?2 ? |
?
?
四、???通常定义常量方法和枚举定义常量方法区别
以下内容可能有些无聊,但绝对值得一窥
1.????代码:
public class State {
public static final int ON = 1;
public static final Int OFF= 0;
}
?
有什么不好了,大家都这样用了很长时间了,没什么问题啊。
首先,它不是类型安全的。你必须确保是int
其次,你还要确保它的范围是0?和1
最后,很多时候你打印出来的时候,你只看到?1?和0?,
?
但其没有看到代码的人并不知道你的企图,抛弃你所有旧的public static final?常量吧
?
2.????可以创建一个enum?类,把它看做一个普通的类。除了它不能继承其他类了。(java?是单继承,它已经继承了Enum),
可以添加其他方法,覆盖它本身的方法
3.????switch()?参数可以使用enum?了
?
4.????values()?方法是编译器插入到enum?定义中的static?方法,所以,当你将enum?实例向上转型为父类Enum?是,values()?就不可访问了。解决办法:在Class?中有一个getEnumConstants()?方法,所以即便Enum?接口中没有values()?方法,我们仍然可以通过Class?对象取得所有的enum?实例
?
5.????无法从enum?继承子类,如果需要扩展enum?中的元素,在一个接口的内部,创建实现该接口的枚举,以此将元素进行分组。达到将枚举元素进行分组。
?
6.????使用EnumSet?代替标志。enum?要求其成员都是唯一的,但是enum?中不能删除添加元素。
?
7.????EnumMap?的key?是enum?,value?是任何其他Object?对象。
?
8.????enum?允许程序员为eunm?实例编写方法。所以可以为每个enum?实例赋予各自不同的行为。
?
9.????使用enum?的职责链(Chain of Responsibility) .?这个关系到设计模式的职责链模式。以多种不同的方法来解决一个问题。然后将他们链接在一起。当一个请求到来时,遍历这个链,直到链中的某个解决方案能够处理该请求。
?
10.???使用enum?的状态机
?
11.???使用enum?多路分发