Java 005 枚举

public final String name()
Returns the name of this enum constant, exactly as declared in its enum declaration. Most programmers should use the toString() method in preference to this one, as the toString method may return a more user-friendly name. This method is designed primarily for use in specialized situations where correctness depends on getting the exact name, which will not vary from release to release.

public String toString()
Returns the name of this enum constant, as contained in the declaration. This method may be overridden, though it typically isn't necessary or desirable. An enum type should override this method when a more "programmer-friendly" string form exists.

System.out.println(Week.Monday) ---> Week.Monday 默认调用toString()方法

枚举概述:就是有有限值的集合或类。
是指将变量的值一一列出来, 变量的值只限于列举出来的值得范围。 举例: 一周7天, 一年12个月等。
回想单列设计模式: 单例类是一个类只有一个实例。
那么多例类就是一个类有多个实例, 但不是无限个数的实例, 而是有限个数的实例。 这才能是枚举类。

通过自定义一个枚举类:

 // 第一版:Simple
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
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
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();
}
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 output ----
-------------- User Defined Enum - Simple ----------------------
com.java.test.UD_Enum@1db9742
-------------- User Defined Enum - Medium ----------------------
com.java.test.UD_Enum2@106d69c
LEFT
-------------- User Defined Enum - Implex ----------------------
com.java.test.UD_Enum3$4@52e922
RIGHT
this is right

发现自定义一个枚举类比较麻烦, 所以java就提供了枚举类供我们使用。
格式是: 只有枚举项的枚举类

public enum 枚举类名{
  枚举项1, 枚举项2, 枚举项3.........;
}

 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;
}
}
}

注意事项:

  • 定义枚举类要用关键字Enum
  • 所有枚举类都是Enum的子类
  • 枚举类的第一行必须是枚举项, 最后一个枚举项的分号是可以省略的, 但是如果枚举类有其他的东西, 这个分号不能省略。 建议不要省略
  • 枚举类也可以由构造函数, 但必须是private的, 它默认的也是private的。 枚举项的用法比较特殊, 枚举("")
  • 枚举类也可以有抽象方法, 但是枚举项必须重写该方法
  • 枚举在switch语句中的使用
 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();
} 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;
}
}

枚举和类常量的对比:
1. 枚举类型是强类型的,从而保证了系统安全性。而以类的静态字段实现的类来替代枚举,不具有枚举的简单性和类型安全性。
把一个表示星期一到星期天的枚举类作为方法参数的时, 只能传递枚举项 限制了可以传递的范围 重点是限制 他给你类型 然后你去选择类型 这跟以前的判断方式肯定是不同的
枚举可以限定参数的个数,对调用者的行为能更加严格地进行控制。把一些运行期的参数检查放到了编译期,做到这点是一个很大的进步。 int 1-7 表示星期一到星期天, 作为参数传递时, 比如 0, 9 来调编译不会报错, 运行是就会出错。 枚举类型则可以将一个类型限制在可控制的范围内。

2. 枚举类型使代码更具可读性,理解清晰,易于维护。方便的代码机制。同时,如果枚举符号和对应的整数值发生变化,只需修改枚举定义即可,而不必在漫长的代码中进行修改。
表示星期1-7,你可以用int1-7,但是当你把它作为参数的时候,有时后你就给考虑传入0,8的情况.而且用数字表示还需要相应的注释和文档. 这个时候你定义个一个枚举,名字就叫字面就叫Monday , Tuesday ,....就行,直观,并且值可控.
如果要定义100个常量时候 你就知道枚举的好处了 包糖衣还是很有用的

静态常量其实是枚举模式的应用, 但它有很多缺点
* 类型不安全(静态常量可以随意增加使用或操作)
* 无命名空间,
* 脆弱(某常量值改变后客户端如果不编译热人仍能使用)
* 静态常量打印值为数字
* 不具有提示性

假如有一笔业务需要审核,审核状态分:未审核,审核中,审核通过,审核不通过。我们在程序里是否可以直接这么写:
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;
}
public int getStatenum() {
return statenum;
}
}
调用如下:
if (state == AuditState.UNAUDIT.getStatenum()) {
//AuditState.UNAUDIT.toString()获取字符串描述
System.out.println(AuditState.UNAUDIT.toString() + "标识是 "
+ AuditState.UNAUDIT.getStatenum());
} else {
//......
}
枚举类还有更加强大的功能,如添加字段,方法,还可以对他进行遍历访问

虽然枚举在很多方面都比接口常量和类常量好用,但是它有一点比不上接口常量和类常量的,就是继承,枚举类型是不能有继承的,也就是说一个枚举常量定义完毕后,除非修改重构,否则无法做扩展。

三、建议
在项目开发中,推荐使用枚举常量代替接口常量或类常量。

上一篇:虚拟机Visualbox安装Ubuntu Server


下一篇:sql server 关于表中只增标识问题 C# 实现自动化打开和关闭可执行文件(或 关闭停止与系统交互的可执行文件) ajaxfileupload插件上传图片功能,用MVC和aspx做后台各写了一个案例 将小写阿拉伯数字转换成大写的汉字, C# WinForm 中英文实现, 国际化实现的简单方法 ASP.NET Core 2 学习笔记(六)ASP.NET Core 2 学习笔记(三)