在博客系统中,一篇文章有且可能有这几种状态, 数据库中article
文章表中state
字段存储数值,表示其状态:java
文章实体类中用整数类型的state实例变量标识状态:程序员
public class Article { /* 文章状态可能值:0,1,2 */ private int state; ... }
Service
层调用DAO
层修改文章状态为‘已发表’:数据库
/** * dao接口修改文章状态方法 * @param articleId 文章ID * @param state 状态 */ int updateState(int articleId, int state); // `Service`层修改文章状态的调用Dao代码: articleDao.updateState(id, 0);
以上代码有两个问题:编程
state
参数传递并无限定范围(0,1,2);先来解决第二个问题, 在JDK1.5前经常使用的解决方式:mybatis
/** * 定义了文章的状态 */ public interface ArticleState{ // 发布状态 int PUBLISHED = 0; // 草稿状态 int DRAFT = 1; // 撤回状态 int DELETE = 2; }
此时修改文章状态的代码:函数
articleDao.updateState(id, ArticleState.PUBLISHED);
然而此处没有限制必须经过ArticleState
传递参数,JDK1.5后提供了枚举来解决这类问题。工具
在java中,使用enum
关键字声明枚举类测试
/** * 文章状态枚举类 */ public enum ArticleStateEnum{ PUBLISHED, DRAFT, DELETE; }
而后修改DAO接口:this
/** * dao接口修改文章状态方法 * @param articleId 文章ID * @param state 状态 */ int updateState(int id, ArticleStateEnum state);
接着Service调用:code
// 修改文章状态为发表 articleDao.updateState(id, ArticleStateEnum.PUBLISHED);
以上代码语义清晰,如今传递参数的类型为ArticleStateEnum
, 解决了以前描述的两个问题
使用JDK附带工具javap
反编译生枚举类字节码, 注javap反编译只会获得public成员:
看反编译的获得的代码:
java.lang.Enum<>
, 意味着枚举类不容许显式使用extends声明父类,包括声明为java.lang.Enum<>
也会报错;public static final
修饰符实现,ArticlestateEnum
类型声明,意味着全部枚举常量本质是当前枚举类的对象;values()方法
,valueOf(String)方法
;这些转换工做是javac
编译器帮咱们实现的,JVM并不知道枚举的存在,javac帮咱们作了一些语法上的转化、简化程序员编程,这种方式称为语法糖。
枚举类就是类,按照这个逻辑来测试下它和普通类的差异
添加构造函数:
红色行提示编译错误“找不到这样的构造函数”,常量声明处添加参数,以下代码正确:
public enum ArticleStateEnum{ PUBLISHED(0, "已发布"), DRAFT(1, "草稿"), DELETE(2, "撤销"); /** 表明的数值 */ private int value; /** 信息提示 */ private String message; ArticleStateEnum(int value, String message) { this.value = value; this.message = message; } // get方法 }
能够推测到常量声明的地方,等价于调用构造函数,一般咱们都会为字段添加GET方法不添加SET方法,保证枚举常量的不变性。
枚举类VS普通类的不一样点:
private
;看看如下如此夸张的写法,也能编译成功:
观察生成的字节码文件:
把枚举常量声明的地方替换成构造方法调用new ArticleStateEnum(v1, m1)
,这不就是匿名类的声明吗!
如今向枚举类内添加抽象方放,看看结果:
编译报错“提示有抽象方法未实现”,验证了前面的猜测,这是匿名类的实现,不过不能够显式的使用使用匿名实现枚举类的方式!
详细参见API文档Enum类:
public enum ArticleStateEnum{ PUBLISHED, DRAFT, DELETE; public static void main(String[] args) { ArticleStateEnum[] states = ArticleStateEnum.values(); // 1. 得到全部枚举常量 for(ArticleStateEnum state: states) { System.out.println("序号:" + state.ordinal() + " 名字:" + state); //2. 输出声明序号和名称 } System.out.println("......................................"); ArticleStateEnum draft = ArticleStateEnum.valueOf("DRAFT"); //3. 得到某个枚举常量,依据字符串 if(ArticleStateEnum.DRAFT == draft) { System.out.println(ArticleStateEnum.valueOf("DRAFT").name()); //4. name方法输出名字 } } }
输出...
序号:0 名字:PUBLISHED 序号:1 名字:DRAFT 序号:0 名字:DELETE DRAFT
java中枚举给咱们带来强大的语义的时候,又因为枚举常量对象的本质,给咱们带了来庞大性,不如C语言的枚举的轻量:
在mybatis中保存带有枚举字段的实体时,须要你编写转化器(除非按照默认的声明顺序);
转化为JSON数据时;
建议无特殊状况仍是使用枚举常量,毕竟软件的正确性是最重要的