枚举类
使用场景:一个类的对象固定且有限(一般用来定义返回码、状态码)
产生原因:有明确的意义,固定且不能被更改(比static final设定强而且安全)
定义:使用 enum关键字,跟定义一个类相同,枚举类是一种特殊的类。第一行定义的是实例,使用逗号分隔。
public enum EnumDemo1 {
SPRING,SUMMER,WINTER;
}
特征
- 父类是java.lang.Enum类,不能继承其他类,间接实现了java.lang.Serializable和java.lang.Comparable接口
- 定义的非抽象枚举类,默认是final类,其定义的实例对象也均是public static final
- 其构造器必须是private,如果没有显示指定默认也是private
- 其所有实例必须在第一行显示指定,否则该枚举类永远不能产生实例
遍历枚举实例
// 枚举类默认提供了一个values()方法,可以用来迭代获取枚举实例
public enum EnumDemo1 {
SPRING,SUMMER,WINTER;
public static void main(String[] args) {
for (EnumDemo1 obj : EnumDemo1.values()) {
System.out.println(obj);
}
}
}
Enum API详解
-
int compareTo(E o):比较枚举实例的顺序,定义在对象o前面返回的是负值,在对象o之后返回正值。说人话(enum1.compareTo(enum2) 返回值为 ==enum1的索引值 - enum2的索引值 + 1==)
System.out.println(SPRING.compareTo(SUMMER)); // -1
String name():返回枚举值的名称
String toString():返回枚举值的名称,同name方法的作用是一样的,源码二者均是返回的name
int ordinal():返回枚举值的索引值,第一个默认是0
readObject(ObjectInputStream in)和readObjectNoData(),保证常量实例唯一, 重写覆盖默认序列化规则
参考:https://stackoverflow.com/questions/34589325/why-default-serialization-is-prevented-in-enum-class
- public static
> T valueOf(Class enumType,String name):返回指定枚举类中指定名称的枚举值
System.out.println(Enum.valueOf(EnumDemo1.class,"SPRING"));
抽象枚举类
抽象枚举类不需要使用abstract显示声明,里面定义一个抽象方法就表示该枚举类是一个抽象枚举类,与普通抽象类相似
public enum EnumDemo3{
OK{
@Override
public void info() {
// todo
}
};
public abstract void info();
}
编译后发现,系统会自动给它添加abstract,同时生成一个OK的匿名class
Compiled from "EnumDemo3.java"
public abstract class enumdemo.EnumDemo3 extends java.lang.Enum {
public static final enumdemo.EnumDemo3 OK;
public static enumdemo.EnumDemo3[] values();
Code:
0: getstatic #2 // Field $VALUES:[Lenumdemo/EnumDemo3;
3: invokevirtual #3 // Method "[Lenumdemo/EnumDemo3;".clone:()Ljava/lang/Object;
6: checkcast #4 // class "[Lenumdemo/EnumDemo3;"
9: areturn
实际使用
原先的项目组里面是使用一个Constant类定义整个项目里面常用的常量和返回码、错误码、业务码,挺乱的而且容易忘记还需要经常维护查看对应的业务信息。
后面升级就使用了枚举类进行改造,定义一个接口控制总的行为,根据具体的功能和业务去实现对应的常量信息。
后面项目组解散换了一个古老的项目,它把编码放在一个常量类里面,然后定义的变量和对应的业务文字描述用一个键值对的方式放在一个code.properties文件里面(坑爹)。重点是这个文件的格式是ANSI,使用eclipse会自动把汉字解析出来,但是我用的是idea尼玛全是一堆16进制字符,整的我没脾气了,问了项目组的人咋个设计成这个样子(遗留问题,不晓得,吐血)。
idea中自动将ANSI中的数据解析设置:settings ----> Editor ----> File Encodings ----> 勾选 Transparent native-to-ascii conversion。
这样弄我没感觉到有什么优势,每次使用都要根据key去文件里面拿一边特别不方便,查对应的业务编码信息的时候还需要去找到这个文件然后在find一下,感觉有种脑子被门夹的感觉。
改造
public interface EnumPower {
public String getCode();
public String getMessage();
}
public enum ReturnCode implements EnumPower{
SUCCESS("0","成功"),
FAIL("1","失败");
private final String code = null;
private final String message = null;
private static Hashtable aliasEnums;
ReturnCode(String code, String message) {
this.code = code;
this.message = message;
this.init(code, message);
}
private void init(String code, String message) {
synchronized (this.getClass()) {
if (aliasEnums == null) {
aliasEnums = new Hashtable();
}
}
aliasEnums.put(code, this);
aliasEnums.put(message, this);
}
public static ReturnCode valueOfAlias(String alias) {
return aliasEnums.get(alias);
}
public static ReturnCode valueOfAlias(char alias) {
return aliasEnums.get(String.valueOf(alias));
}
@Override
public String getCode() {
return this.code;
}
@Override
public String getMessage() {
return this.message;
}
@Override
public String toString() {
return this.getMessage() + "〔信息代码:" + this.getCode() + "〕";
}
}
总结:
系统会为枚举类自动创建里面定义好的实例,因此它的构造方法必须是private。
枚举类也是类,所以构造方法里面也可以带参数,它的特性就决定了它能够自带业务信息在里面
不好的一点是不能通过定义的实例反向定位被调用的地方,只能通过搜索SUCCESS来确定,所以一般定义之后不要去改,否则你又不确定改完之后所有调用的地方都符合你要的业务就会有问题。