枚举和常量的对比:
1. 枚举类型更安全
把一个表示星期一到星期天的枚举类作为方法参数的时, 只能传递枚举项 限制了可以传递的范围。 传递其他参数 编译就会报错
而如果你定一个常量 int 1-7 表示星期一到星期天, 作为参数传递时, 比如 0, 9 来调编译不会报错, 运行是就会出错
2. 枚举类型是代码更具有可读性, 理解清晰, 易于维护
定义常量表示 还需要相应的注释和文档
如果要定义100个常量时候 你就知道枚举的好处了 包糖衣还是很有用的
静态常量是枚举模式的应用, 但它有很多缺点
* 类型不安全(静态常量可以随意增加使用或操作)
* 无命名空间,
* 脆弱(某常量值改变后客户端如果不编译热人仍能使用)
* 静态常量打印值为数字
* 不具有提示性
package com.java.enumlearn;
public class EnumUtil {
public static enum Browser {
CHROME,
IE,
FIREFOX,
HTMLUNIT
}
/**
* ReportOptions.Client.name() -- 内置的方法, 返回自身的字符串值 比如 返回的是 Client
* 既然枚举类型提供了构造函数,我们可以通过构造函数和覆写toString 方法来实现。
* 首先给枚举类型增加构造方法,然后每个枚举类型的值通过构造函数传入对应的参数,
* 同时覆写toString 方法,在该方法中返回从构造函数中传入的参数,改造后的代码如下:
* @author LL-CC
*
*/
public static enum ReportOptions{
Client("Client Document Upload"),
Color("Report Color Upload"),
Position("Report Position Upload");
private String value;
private ReportOptions(String value){
this.value = value;
}
public String toString() {
return this.value;
}
}
}
枚举概述:就是有有限值的集合或类。
- 是指将变量的值一一列出来, 变量的值只限于列举出来的值得范围。 举例: 一周7天, 一年12个月等。
- 回想单列设计模式: 单例类是一个类只有一个实例。
- 那么多例类就是一个类有多个实例, 但不是无限个数的实例, 而是有限个数的实例。 这才能是枚举类。
通过自定义一个枚举类演示案例:
第一版:Simple
package com.java.test;
public class UD_Enum {
public static final UD_Enum FRONT = new UD_Enum();
public static final UD_Enum BEHIND = new UD_Enum();
public static final UD_Enum LEFT = new UD_Enum();
public static final UD_Enum RIGHT = new UD_Enum();
private UD_Enum(){
}
}
第二版:Medium
package com.java.test;
public class UD_Enum2 {
public static final UD_Enum2 FRONT = new UD_Enum2("FRONT");
public static final UD_Enum2 BEHIND = new UD_Enum2("BEHIND");
public static final UD_Enum2 LEFT = new UD_Enum2("LEFT");
public static final UD_Enum2 RIGHT = new UD_Enum2("RIGHT");
private String name;
public String getName(){
return this.name;
}
private UD_Enum2(String name){
this.name = name;
}
private UD_Enum2(){
}
}
第三版: Complex
package com.java.test;
public abstract class UD_Enum3 {
public static final UD_Enum3 FRONT = new UD_Enum3("FRONT"){
@Override
public void show() {
System.out.println("this is front");
}
};
public static final UD_Enum3 BEHIND = new UD_Enum3("BEHIND"){
@Override
public void show(){
System.out.println("this is behind");
}
};
public static final UD_Enum3 LEFT = new UD_Enum3("LEFT"){
@Override
public void show(){
System.out.println("this is left");
}
};
public static final UD_Enum3 RIGHT = new UD_Enum3("RIGHT"){
@Override
public void show(){
System.out.println("this is right");
}
};
private String name;
public String getName(){
return this.name;
}
private UD_Enum3(String name){
this.name = name;
}
private UD_Enum3(){
}
public abstract void show();
}
测试类:
package com.java.test;
public class EnumDemo {
public static void main(String[] args){
System.out.println("-------------- User Defined Enum - Simple ----------------------");
UD_Enum ud1 = UD_Enum.BEHIND;
System.out.println(ud1);
System.out.println("-------------- User Defined Enum - Medium ----------------------");
UD_Enum2 ud2 = UD_Enum2.LEFT;
System.out.println(ud2);
System.out.println(ud2.getName());
System.out.println("-------------- User Defined Enum - Implex ----------------------");
UD_Enum3 ud3 = UD_Enum3.RIGHT;
System.out.println(ud3);
System.out.println(ud3.getName());
ud3.show();
}
}
Console
发现自定义一个枚举类比较麻烦, 所以java就提供了枚举类供我们使用。
格式是: 只有枚举项的枚举类
public enum 枚举类名{
枚举项1, 枚举项2, 枚举项3.........;
}
注意事项:
- 定义枚举类要用关键字Enum
- 所有枚举类都是Enum的子类
- 枚举类的第一行必须是枚举项, 最后一个枚举项的分号是可以省略的, 但是如果枚举类有其他的东西, 这个分号不能省略。 建议不要省略
- 枚举类也可以由构造函数, 但必须是private的, 它默认的也是private的。 枚举项的用法比较特殊, 枚举("")
- 枚举类也可以有抽象方法, 但是枚举项必须重写该方法
- 枚举在switch语句中的使用
package com.java.test;
public enum EnumComplex {
FRONT("front") {
@Override
public void show() {
System.out.println("I choose front");
}
}, BEHIND("behind") {
@Override
public void show() {
System.out.println("I choose behind");
}
}, LEFT("left") {
@Override
public void show() {
System.out.println("I choose left");
}
}, RIGHT("right") {
@Override
public void show() {
System.out.println("I choose right");
}
};
private String name;
public String getName(){
return name;
}
private EnumComplex(String name){
this.name = name;
}
public abstract void show();
}
package com.java.test;
public class EnumDemo {
public static void main(String[] args){
System.out.println("-------------- Java Enum - Simple ----------------------");
EnumSimple ed1 = EnumSimple.RIGHT;
System.out.println(ed1);
System.out.println("-------------- Java Enum - Complex ----------------------");
EnumComplex ed2 = EnumComplex.LEFT;
System.out.println(ed2);
System.out.println(ed2.getName());
ed2.show();
switch(ed2){
case FRONT:
System.out.println("front");
break;
case BEHIND:
System.out.println("Behind");
break;
case LEFT:
System.out.println("left");
break;
case RIGHT:
System.out.println("right");
break;
}
}
}
假如有一笔业务需要审核,审核状态分:未审核,审核中,审核通过,审核不通过。我们在程序里是否可以直接这么写:
if(state==1){//1代表未操作
//操作
}else{
//......
}
将状态标识直接写在代码里面(硬编码),只图一时方便,却是后患无穷,如果有一天你需要修改状态标识,用0代表未审核而不是1,你不得不将所有与该标识相关的代码都找出来一个个改,另外,在编码过程中,标识输入错误的概率是比较高的,一不小心把0输入成了10,虽然不会提示任何编译错误,但运行结果将是出乎人的意料的。
于是我们很快想到可以用常量代替:
public static final int UNAUDIT = 0;
相关判断代码则是:
if(state==CONSTANT.UNAUDIT){
//操作
}else{
//......
}
这段代码比硬编码更加健壮容易维护,但是仍然有不足之处。
1、UNAUDIT是编译期常量,如果其值被改变,那么使用方需要重新编译。
2、没有简便的方法获取标识代表的字符串描述。
于是我们用枚举类来代替常量。
public enum AuditState {
UNAUDIT(1),
AUDITING(2),
AUDIT_SUCCESS(3),
AUDIT_FAIL(4);
private final int statenum;
AuditState(int statenum){
this.statenum = statenum;
}
publicint getStatenum() {
return statenum;
}
}
调用如下:
if (state == AuditState.UNAUDIT.getStatenum()) {
//AuditState.UNAUDIT.toString()获取字符串描述
System.out.println(AuditState.UNAUDIT.toString() + "标识是 "
+ AuditState.UNAUDIT.getStatenum());
} else {
//......
}
枚举类还有更加强大的功能,如添加字段,方法,还可以对他进行遍历访问
一、分析
常量的声明是每一个项目中不可或缺的,在Java1.5之前,我们只有两种方式的声明:类常量和接口常量。不过,在1.5版之后有了改进,即新增了一种常量声明方式,枚举常量。
代码如下:
- enum Season{
- }
那么枚举常量与我们的经常使用的类常量和静态常量比有什么优势呢?
1.枚举常量更简单
先把Season枚举翻译成接口,代码如下:
- interface Season{
- int0 int Summer = 1;
- int2 int Winter = 3;
- 枚举只需要定义每个枚举项,不需要定义枚举值,而接口常量(或类常量)则必须定义值,否则编译通不过;两个引用的方式相同(都是“类名.属性”,如Season.Sprint),但是枚举表示的是一个枚举项,字面含义是春天,而接口常量却是一个Int类型。
2.枚举常量属于稳态型
使用常量接口,我们得对输入值进行检查,确定是否越界,如果常量非常庞大,校验输入就是一件非常麻烦的事情,但这是一个不可逃避的过程。
- public void describe(int s){
- //s变量不能超越边界,校验条件 if(s >= 0 && s <4){
- switch case Season.Summer:
- "Summer is very hot!" break;
- case System.out.println("Winter is very cold!");
- break …..
- }
- 我们再来看看枚举常量是否能够避免校验问题,代码如下:
- public void describe(Season s){
- switch case Season.Summer:
- "Summer is very hot!" break;
- case System.out.println("Winter is very cold!");
- break …...
- }
不用校验,已经限定了是Season枚举,所以只能是Season类的四个实例。这也是我们看重枚举的地方:在编译期间限定类型,不允许发生越界的情况。
3.枚举具有内置方法
每个枚举都是
Java.lang.Enum的子类,该基类提供了诸如获得排序值的ordinal方法、compareTo比较方法等,大大简化了常量的访问。比如,列出所有枚举值:
- public static void main(String[] args){
- for System.out.println(s);
- }
4.枚举可以自定义方法
这一点似乎不是枚举的优点,类常量也可以有自己的方法,但关键是枚举常量不仅仅可以定义静态方法,还可以定义非静态方法,而且还能够从根本上杜绝常量类被实例化。比如我们在定义获取最舒服的季节,使用枚举的代码如下:
- enum Season{
- //最舒服的季节
- publicstatic return Spring;
- }
那如果是使用类常量如何实现呢?如下:
- class Season{
- publicfinalstaticint0 public final static int Summer = 1;
- publicfinalstaticint2 public final static int Winter = 3;
- //最舒服的季节
- publicstaticint return Spring;
- }
虽然枚举在很多方面都比接口常量和类常量好用,但是它有一点比不上接口常量和类常量的,就是继承,枚举类型是不能有继承的,也就是说一个枚举常量定义完毕后,除非修改重构,否则无法做扩展。
三、建议
在项目开发中,推荐使用枚举常量代替接口常量或类常量。
Java 005 枚举
原文:http://www.cnblogs.com/zi-yao/p/6246446.html