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类型。
还有很多等待探究。