说实话,本人之前对java的枚举并不是特别的了解,直到到了新公司,看到好多都在用枚举,渐渐的了解了。在这里我总结一下,查漏补缺吧。
一、优点
1)增强代码可读性。
2)传递参数错误。
3)去除equals两者判断:由于常量值地址唯一,使用枚举可以直接通过“==”进行两个值之间的对比,性能会有所提高。
4)编译优势(与常量类相比):常量类编译时,常量被直接编译进二进制代码中,常量值在升级中变化后,需要重新编译引用常量的类,因为二进制代码中存放的是旧值。枚举类编译时,没有把常量值编译到代码中,即使常量值发生改变,也不会影响引用常量的类。
5)修改优势(与常量类相比):枚举类编译后默认final class,不允许继承可防止被子类修改。常量类可被继承修改、增加字段等,易导致父类不兼容。
6)枚举型可直接与数据库交互。
7)Switch语句优势:使用int、String类型switch时,当出现参数不确定的情况,偶尔会出现越界的现象,这样我们就需要做容错操作(if条件筛选等),使用枚举,编译期间限定类型,不允许发生越界。
二、创建
这是一个最基本的枚举定义,我感觉有以下几个特点:
1) 定义时,使用了关键字 enum ,而不是class,或者interface;使用了enum,相当于被 static(能静态调用),final(不能被重写)修饰;
2) 枚举的成员一般大写,之间用逗号,末尾用封号;
3) 枚举也需要构造方法、属性、setter方法、getter方法;
4) 尽量避免使用java.lang.Enum中的已有属性,如name,ordinal。不然可能会混淆——下文涉及;
5) 尽量避免使用ordinal属性判断枚举成员。因为ordinal属性返回成员的索引,如下代码MAN返回0,WOMAN返回1,但是只要你在枚举定义的时候,错乱了顺序,或者在枚举成员之前添加新的成员,都会导致ordinal的值发生变化。试想一个例子,假如没有code,你数据库中根据ordinal存入了男(索引0),女(索引1),但是后来随着开发的必要,你感觉应该加一个未知性别,所以你就不小心在MAN和WOMAN的之间加了UNKNOW(2,"未知")。最终是这样 MAN(1,“男”),UNKNOW(2,“未知”),WOMAN(0,“女”),这时WOMAN的ordinal值已经变为了2,不是1了,所以数据库发生脏数据了。所以为了避免发生意外,尽量避免使用,或者严格规定,添加枚举成员只能在后面追加,不能中间插入。
6)构造方法,枚举的构造方法默认是private,而且是强制的;
7)枚举值默认被public static final修饰;
public enum SexEnum { //男 MAN(1, "男"), //女 WOMAN(0, "女"); /** * 属性 */ private int code; private String desc; /** * 构造方法 * @param code * @param desc */ SexEnum(Integer code, String desc) { this.code = code; this.desc = desc; } /** * getter and setter * @return */ public int getCode() { return code; } public void setCode(int code) { this.code = code; } public String getDesc() { return desc; } public void setDesc(String desc) { this.desc = desc; } }
三、API
java里面的枚举自动继承了java.lang.Enum,由于java不能多继承,所以枚举不能再继承其他类了。这是java.lang.Enum的源码,我们看到它实现了Comparable接口,所以java里面的所有枚举都是可以进行比较的。其中有几个重要的方法:
1)name():返回枚举成员的名称;toString就是返回name值。
2)ordinal():返回枚举成员的索引;
3)compareTo():根据ordinal的值比较大小;
a<b,a.compareTo(b) = -1;
a=b,a.compareTo(b) = 0;
a>b,a.compareTo(b) = 1;
4)valueOf():将一个字符串映射成枚举;不存在就转化异常。
5)values():获取该枚举对象的所有枚举值。——该方法暂未找到出处。
package java.lang; import java.io.Serializable; import java.io.IOException; import java.io.InvalidObjectException; import java.io.ObjectInputStream; import java.io.ObjectStreamException; public abstract class Enum<E extends Enum<E>> implements Comparable<E>, Serializable { private final String name; public final String name() { return name; } private final int ordinal; public final int ordinal() { return ordinal; } protected Enum(String name, int ordinal) { this.name = name; this.ordinal = ordinal; } public String toString() { return name; } public final boolean equals(Object other) { return this==other; } public final int hashCode() { return super.hashCode(); } protected final Object clone() throws CloneNotSupportedException { throw new CloneNotSupportedException(); } public final int compareTo(E o) { Enum<?> other = (Enum<?>)o; Enum<E> self = this; if (self.getClass() != other.getClass() && self.getDeclaringClass() != other.getDeclaringClass()) throw new ClassCastException(); return self.ordinal - other.ordinal; } public static <T extends Enum<T>> T valueOf(Class<T> enumType,String name) { T result = enumType.enumConstantDirectory().get(name); if (result != null) return result; if (name == null) throw new NullPointerException("Name is null"); throw new IllegalArgumentException("No enum constant " + enumType.getCanonicalName() + "." + name); } protected final void finalize() { } }
public class EnumTest { /** * name属性:返回枚举名称 */ @Test public void test_name(){ //MAN System.out.println(SexEnum.MAN.name()); //WOMAN System.out.println(SexEnum.WOMAN.name()); } /** * ordinal属性:返回枚举索引 */ @Test public void test_ordinal(){ //0 System.out.println(SexEnum.MAN.ordinal()); //1 System.out.println(SexEnum.WOMAN.ordinal()); } /** * compareTo():根据ordinal的值比较大小 */ @Test public void test_compareTo(){ //-1 System.out.println(SexEnum.MAN.compareTo(SexEnum.WOMAN)); //1 System.out.println(SexEnum.WOMAN.compareTo(SexEnum.MAN)); //0 System.out.println(SexEnum.MAN.compareTo(SexEnum.MAN)); } /** * valueOf():将字符串映射为枚举 */ @Test public void test_valueOf(){ //MAN System.out.println(SexEnum.valueOf("MAN")); //java.lang.IllegalArgumentException: No enum constant SexEnum.MAN123 System.out.println(SexEnum.valueOf("MAN123")); } /** * values():获取该枚举对象的所有枚举值 */ @Test public void test_values(){ SexEnum[] enums = SexEnum.values(); for (SexEnum sexEnum:enums){ //MAN //WOMAN System.out.println(sexEnum); } } }
四、集合
3.1、EnumMap
因为HashMap是一种通过对key计算hashCode(),通过空间换时间的方式,直接定位到value所在的内部数组的索引,因此,查找效率非常高。如果作为key的对象是enum类型,那么,还可以使用Java集合库提供的一种EnumMap,它在内部以一个非常紧凑的数组存储value,并且根据enum类型的key直接定位到内部数组的索引,并不需要计算hashCode(),不但效率最高,而且没有额外的空间浪费。使用EnumMap的时候,我们总是用Map接口来引用它,因此,实际上把HashMap和EnumMap互换,在客户端看来没有任何区别。
3.2、EnumSet
同EnumSet
@Test public void test_EnumMap(){ Map<SexEnum,String> enumMap = new EnumMap<SexEnum, String>(SexEnum.class); enumMap.put(SexEnum.MAN,"这是一个男生"); enumMap.put(SexEnum.WOMAN,"这是一个女生"); } @Test public void test_EnumSet(){ EnumSet enumSet = EnumSet.allOf(SexEnum.class); }
EnumMap、EnumSet的更多资料请查看 java.util.EnumMap实战、java.util.EnumSet实战