Java枚举
枚举类型始于Java5,可能很多同学做了很多年Java开发都没有用到过枚举或者只用于常量标识,而一般很多项目中的常量标识都是String或者int,而使用String和int所带来的风险之一就是非法参数(当然还有参数比较)。那枚举是什么?枚举有什么用呢?
枚举是什么,枚举的实质
假设性别枚举类:男、女、未知,代码如下
public enum Sex {
MALE, FEMALE, UNKNOW
}
然后你可能见过下面这样子也是可以的,可能会想这尼玛什么鬼?
public enum Sex {
MALE(), FEMALE(), UNKNOW()
}
其实枚举的本质还是类,枚举的成员就是声明的静态实例,口说无凭直接javap开搞,javap Sex.class命令执行结果
public final class com.newstart.demo._enum.Sex extends java.lang.Enum<com.newstart.demo._enum.Sex> {
public static final com.newstart.demo._enum.Sex MALE;
public static final com.newstart.demo._enum.Sex FEMALE;
public static final com.newstart.demo._enum.Sex UNKNOW;
public static com.newstart.demo._enum.Sex[] values();
public static com.newstart.demo._enum.Sex valueOf(java.lang.String);
static {};
}
可以看到Sex类继承自java.lang.Enum,类中有三个静态成员变量,都是Sex类的实例而且都是final的。我们一般声明静态常量不也是这样声明的吗?枚举的设计初衷就是提供一组常量。

枚举有什么用,怎么用
-
作为常量使用,比如你要限制某个方法的入参只能是MALE, FEMALE, UNKNOW三者之一
public enum Sex {
MALE, FEMALE, UNKNOW
}
-
switch代码块,其实就是用与对比和判断
public void choose(Sex sex) {
switch (sex) {
default:
case FEMALE:
//do something
break;
case MALE:
//do something
break;
case UNKNOW:
//do something
break;
}
}
-
自定义字段,添加方法
public enum Sex {
MALE(1, "男"),
FEMALE(2, "女"),
UNKNOW(3, "未知");
//代码,比如你数据库实际存1 2 3
private int code;
//描述
private String description;
Sex(int code, String description) {
this.code = code;
this.description = description;
}
public int getCode() {
return code;
}
public void setCode(int code) {
this.code = code;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
}
这个时候可以查看编译后的class文件,发现Sex类的构造方法是这样的:
private Sex(int code, String description) {
this.code = code;
this.description = description;
}
对private,也就是说外部是new不了Sex对象的,上述代码在实际情况中应该去掉setter,这个有违枚举的设计初衷,所以如果可以通过外部来改变它是非常糟糕的设计。
-
单例模式
上述提到枚举的的构造方法是私有的,既然是私有的就可以用来构造单例,简单粗暴
public enum Singleton {
INSTANCE;
private String prefix;
Singleton() {
this.prefix = "枚举说";
}
public void say(String str) {
System.out.println(this.prefix +
":" + str);
}
public static void main(String[] args) {
Singleton.INSTANCE.say("代码如此多娇");
}
}
-
实现接口,因为本质上就是类,所以可以实现接口,但是不能继承,因为枚举都是继承至java.lang.Enum
public interface Likeable {
/**
* 喜欢什么性别
*
* @return
*/
Sex like();
}
public enum Sex
implements Likeable {
MALE {
@Override
public Sex like() {
return FEMALE;
}
},
FEMALE {
@Override
public Sex like() {
return MALE;
}
},
UNKNOW {
@Override
public Sex like() {
return UNKNOW;
}
}
}
想知道更详细的介绍和用法可以阅读《effective java》章节“用接口模拟可伸缩枚举”。
-
使用抽象方法,为每个枚举成员提供不同的行为
public enum Sex {
MALE {
@Override
Sex like() {
return FEMALE;
}
},
FEMALE {
@Override
Sex like() {
return MALE;
}
},
UNKNOW {
@Override
Sex like() {
return UNKNOW;
}
};
/**
* 喜欢什么性别
*
* @return
*/
abstract Sex like();
}
-
枚举集合
java.util.EnumSet和java.util.EnumMap,看到Set和Map就明白是什么意思了。EnumSet提供了很多静态方法创建Set集合,EnumMap中的key必须是Enum类型。
还有很多等待探究。

