1、为什么使用枚举?
以博客网站为例,文章有三种状态:草稿、审核和发布,可将其定义为静态常量:
public class BlogStatus{
public static final int Draft = 1; // 草稿
public static final int Review = 2; // 审核
public static final int Published = 3; // 发布
}
对于一个判断函数judgeBlogStatus()而言,输入参数没有类型的约束,因此传入任意一个int值都是可以的,编译器也不会提出任何警告。
public void judgeBlogStatus(int status){
...
}
此时枚举类型就可以严谨地约束:
public enum BlogStatus{
Draft, Review, Published
}
public void judgeBlogStatus(BlogStatus status){
...
}
2、如何使用Enum
以后台管理系统为例,使用枚举Enum定义用户角色:
public enum UserRole{
ROLE_ROOT_ADMIN; // 系统管理员
ROLE_ORDER_ADMIN; // 订单管理员
ROLE_NORMAL; // 普通用户
}
枚举的基本用法:
UserRole role1 = UserRole.ROLE_ROOT_ADMIN;
UserRole role2 = UserRole.ROLE_ORDER_ADMIN;
UserRole role3 = UserRole.ROLE_NORMAL;
// values()方法:返回所有枚举常量的数组集合
for(UserRole role : UserRole.values()){
System.out.println(role);
}
// 打印:
// ROLE_ROOT_ADMIN
// ROLE_ORDER_ADMIN
// ROLE_NORMAL
// ordinal()方法:返回枚举常量的序数,注意从0开始
System.out.println( role1.ordinal() ); // 打印0
System.out.println( role2.ordinal() ); // 打印1
System.out.println( role3.ordinal() ); // 打印2
// compareTo()方法:枚举常量间的比较
System.out.println( role1.compareTo(role2) ); //打印-1
System.out.println( role2.compareTo(role3) ); //打印-2
System.out.println( role1.compareTo(role3) ); //打印-2
// name()方法:获得枚举常量的名称
System.out.println( role1.name() ); // 打印ROLE_ROOT_ADMIN
System.out.println( role2.name() ); // 打印ROLE_ORDER_ADMIN
System.out.println( role3.name() ); // 打印ROLE_NORMAL
// valueOf()方法:返回指定名称的枚举常量
System.out.println( UserRole.valueOf( "ROLE_ROOT_ADMIN" ) );
System.out.println( UserRole.valueOf( "ROLE_ORDER_ADMIN" ) );
System.out.println( UserRole.valueOf( "ROLE_NORMAL" ) );
switch语句中的Enum
UserRole userRole = UserRole.ROLE_ORDER_ADMIN;
switch (userRole) {
case ROLE_ROOT_ADMIN: // 枚举变量名称比1,2,3数字更好理解
System.out.println("这是系统管理员角色");
break;
case ROLE_ORDER_ADMIN:
System.out.println("这是订单管理员角色");
break;
case ROLE_NORMAL:
System.out.println("这是普通用户角色");
break;
}
3、自定义扩充枚举
扩充UserRole的枚举,加入“角色名——角色编码”的对应关系
public enum UserRole{
ROLE_ROOT_ADMIN("系统管理员", 000000),
ROLE_ORDER_ADMIN("订单管理员", 100000),
ROLE_NORMAL("普通用户", 200000),
;
// 自定义属性
private final String roleName; // 角色名称
privaye final Integer roleCode; // 角色编码
// 自定义构造函数
UserRole(String roleName, Integer roleCode){
this.roleName = roleName;
this.roleCode = roleCode;
}
// 自定义方法
public String getRoleName() {
return this.roleName;
}
public Integer getRoleCode() {
return this.roleCode;
}
public static Integer getRoleCodeByRoleName(String roleName){
for(UserRole enums : UserRole.values()){
if(enums.getRoleName().equals(roleName)){
return enums.getRoleCode();
}
}
return null;
}
}
从上述代码可知,在enum枚举类中完全可以像在普通Class里一样声明属性、构造函数以及成员方法。
4、枚举+接口的使用
以什么角色能干什么事为例,首先定义一个公用的接口RoleOperation,表示不同角色所能做的操作:
public interface RoleOperation{
String op();
}
定义一个枚举类RoleEnum,依次实现RoleOperation接口:
public enum RoleEnum implements RoleOperation{
// 系统管理员(有A操作权限)
ROLE_ROOT_ADMIN{
@Override
public String op() {
return"ROLE_ROOT_ADMIN:" + " has AAA permission";
}
},
// 订单管理员(有B操作权限)
ROLE_ORDER_ADMIN {
@Override
public String op() {
return"ROLE_ORDER_ADMIN:" + " has BBB permission";
}
},
// 普通用户(有C操作权限)
ROLE_NORMAL {
@Override
public String op() {
return"ROLE_NORMAL:" + " has CCC permission";
}
};
}
调用:
public class JudgeRole{
public String judge(String roleName){
// 一行代码搞定if/else判断不同角色
return RoleEnum.valueOf(roleName).op();
}
}
5、枚举与设计模式
1、单例模式
public class Singleton{
// 构造函数私有化,避免外部创建实例
private Singleton(){
}
// 定义一个内部枚举
public enum SingletonEnum{
SEED; // 唯一一个枚举对象,我们称它为“种子选手”!
private Singleton singleton;
SingletonEnum(){
singleton = new Singleton(); // 真正创建实例的地方
}
public Singleton getInstance(){
return singleton;
}
}
public static Singleton getInstance(){
// 通过枚举的种子选手来获取实例
return SingletonEnum.SEED.getInstance;
}
}
2、策略模式 使用枚举写一个基于策略模式的计算器
public class Test{
public enum Calculator{
ADDITION{
public Double execute(Double x, Double y){
return x + y; // 加法
}
},
SUBTRACTION {
public Double execute( Double x, Double y ) {
return x - y; // 减法
}
},
MULTIPLICATION {
public Double execute( Double x, Double y ) {
return x * y; // 乘法
}
},
DIVISION {
public Double execute( Double x, Double y ) {
return x/y; // 除法
}
};
public abstract Double execute(Double x, Double y);
}
public static void main(String[] args) {
System.out.println( Calculator.ADDITION.execute( 4.0, 2.0 ) );
// 打印 6.0
System.out.println( Calculator.SUBTRACTION.execute( 4.0, 2.0 ) );
// 打印 2.0
System.out.println( Calculator.MULTIPLICATION.execute( 4.0, 2.0 ) );
// 打印 8.0
System.out.println( Calculator.DIVISION.execute( 4.0, 2.0 ) );
// 打印 2.0
}
}
6、枚举的集合类
1、EnumSet
public enum UserRole{
ROLE_ROOT_ADMIN, // 系统管理员
ROLE_ORDER_ADMIN, // 订单管理员
ROLE_NORMAL // 普通用户
}
后台系统新增了一批人,现在需要查看他们是不是某个角色中的一个:
// 定义管理员角色的专属集合
EnumSet<UserRole> userRolesForAdmin = EnumSet.of(
UserRole.ROLE_ROOT_ADMIN;
UserRole.ROLE_ORDER_ADMIN;
);
// 判断某个进来的用户是否是管理员
Boolean isAdmin(User user){
if(userRolesForAdmin.contains(user.getRoleName())){
return true;
}
return false;
}
2、EnumMap 系统里来了一批人,我们需要统计不同的角色到底有多少人:
Map<UserRole, Integer> userStatisticMap = new EnumMap<>(UserRole.class);
for(User user : userList){
Integer num = userStatisticMap.get(user.getUserRole());
if(num != num){
userStatisticMap.put(user.getUserRole(), num + 1);
}else{
userStatisticMap.put(user.getUserRole(), 1);
}
}