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