Java 枚举详解
为什么要用枚举
在博客系统中,一篇文章有且可能有这几种状态, 数据库中article文章表中state字段存储数值,表示其状态:
- 0(已发表Published)
- 1(草稿Draft)
- 2(撤回撤回(Delete)
文章实体类中用整数类型的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);- 传递数据参数的代码,缺少语义,不看文档或注释不知道0是什么含义;
先来解决第二个问题, 在JDK1.5前常用的解决方式:
/**
* 定义了文章的状态
*/
public interface ArticleState{
// 发布状态
int PUBLISHED = 0;
// 草稿状态
int DRAFT = 1;
// 撤回状态
int DELETE = 2;
}
此时修改文章状态的代码:
articleDao.updateState(id, ArticleState.PUBLISHED);
然而此处没有限制必须通过ArticleState传递参数,JDK1.5后提供了枚举来解决这类问题。
Java中声明
在java中,使用enum关键字声明枚举类
/**
* 文章状态枚举类
*/
public enum ArticleStateEnum{
PUBLISHED,
DRAFT,
DELETE;
}
然后修改DAO接口:
/**
* dao接口修改文章状态方法
* @param articleId 文章ID
* @param state 状态
*/
int updateState(int id, ArticleStateEnum state);
接着Service调用:
// 修改文章状态为发表
articleDao.updateState(id, ArticleStateEnum.PUBLISHED);
以上代码语义清晰,现在传递参数的类型为ArticleStateEnum, 解决了之前描述的两个问题
枚举的本质
使用JDK附带工具javap反编译生枚举类字节码, 注javap反编译只会得到public成员:

看反编译的得到的代码:
- class声明,意味着枚举的本质也是类;
- 父类声明为
java.lang.Enum<>, 意味着枚举类不允许显式使用extends声明父类,包括声明为java.lang.Enum<>也会报错; - 枚举常量,通过
public static final修饰符实现,ArticlestateEnum类型声明,意味着所有枚举常量本质是当前枚举类的对象; values()方法,valueOf(String)方法;
这些转换工作是javac编译器帮我们实现的,JVM并不知道枚举的存在,javac帮我们做了一些语法上的转化、简化程序员编程,这种方式称为语法糖。
枚举类VS普通类
枚举类就是类,按照这个逻辑来测试下它和普通类的差别
添加构造函数:

红色行提示编译错误“找不到这样的构造函数”,常量声明处添加参数,如下代码正确:
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; - 其他地方同类一般无二,可以添加自定添加(方法、字段,抽象成员), 实现接口;
枚举类VS匿名类
看看以下如此夸张的写法,也能编译成功:

观察生成的字节码文件:

把枚举常量声明的地方替换成构造方法调用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中枚举的缺点
java中枚举给我们带来强大的语义的时候,又由于枚举常量对象的本质,给我们带了来庞大性,不如C语言的枚举的轻量:
- 枚举常量不可以像C语言一样使用移位运算。
- 枚举常量和外部交互麻烦,比如:
在mybatis中保存带有枚举字段的实体时,需要你编写转化器(除非按照默认的声明顺序);
转化为JSON数据时;
- Spring MVC对请求参数封装时,需要自定义转换器;
- 枚举常量无法继承,意味着相似的枚举类之间无法继承,导致产生冗余代码;
建议无特殊情况还是使用枚举常量,毕竟软件的正确性是最重要的
Java 枚举详解的更多相关文章
- java枚举详解
枚举的本质是类,枚举是用来构建常量数据结构的模板(初学者可以以此方式理解: public static final X=xxx),枚举的使用增强了程序的健壮性,在引用一个不存在的枚举值的时候,编译器会 ...
- Java Annotation详解 理解和使用Annotation
系统中用到了java注解: 查了一下如何使用注解,到底注解是什么: (1)创建方法:MsgTrace Java Class==> 在Create New Class中: name:输入MsgTr ...
- Java IO 详解
Java IO 详解 初学java,一直搞不懂java里面的io关系,在网上找了很多大多都是给个结构图草草描述也看的不是很懂.而且没有结合到java7 的最新技术,所以自己来整理一下,有错的话请指正, ...
- java关键字(详解)
目录 1. 基本类型 1) boolean 布尔型 2) byte 字节型 3) char 字符型 4) double 双精度 5) float 浮点 6) int 整型 7) long 长整型 8) ...
- Java集合详解3:Iterator,fail-fast机制与比较器
Java集合详解3:Iterator,fail-fast机制与比较器 今天我们来探索一下LIterator,fail-fast机制与比较器的源码. 具体代码在我的GitHub中可以找到 https:/ ...
- Java集合详解3:一文读懂Iterator,fail-fast机制与比较器
<Java集合详解系列>是我在完成夯实Java基础篇的系列博客后准备开始写的新系列. 这些文章将整理到我在GitHub上的<Java面试指南>仓库,更多精彩内容请到我的仓库里查 ...
- Java集合详解1:一文读懂ArrayList,Vector与Stack使用方法和实现原理
本文非常详尽地介绍了Java中的三个集合类 ArrayList,Vector与Stack <Java集合详解系列>是我在完成夯实Java基础篇的系列博客后准备开始写的新系列. 这些文章将整 ...
- 9种Java单例模式详解(推荐)
单例模式的特点 一个类只允许产生一个实例化对象. 单例类构造方法私有化,不允许外部创建对象. 单例类向外提供静态方法,调用方法返回内部创建的实例化对象. 懒汉式(线程不安全) 其主要表现在单例类在外 ...
- Java内部类详解
Java内部类详解 说起内部类这个词,想必很多人都不陌生,但是又会觉得不熟悉.原因是平时编写代码时可能用到的场景不多,用得最多的是在有事件监听的情况下,并且即使用到也很少去总结内部类的用法.今天我们就 ...
随机推荐
- oozie配置安装与原理
概述 当前开源的hadoop任务工作流管理主要有oozie和Azkaban,本文先介绍oozie的配置安装与基本运行原理. 配置安装 (参考https://segmentfault.com/a/11 ...
- V3学院XILINX FPGA寒假班培训感受 江苏大学 电子信息科学与技术 邓普建
事先申明一点,我是大一的学生,因此会站在一个新生的角度叙述. 刚开始接触V3学院是在江苏大学与V3学院合办的FPGA/SOC培训中,那是对全校开放的免费培训,历时三个周末.我那时有幸从头听到了尾,觉得 ...
- 非名校毕业年薪20W程序员 心得分享
大家好,我是落落http://blog.csdn.net/robinson1988/ QQ692162374,其实我选择Oracle是一件很神奇的事情,但是现在回想起来又觉得是命中注定.我2006年就 ...
- jQuery DataTable 删除数据后重新加载
问题描述: 利用jQuery Datatable和artTemplate组合来做的表格.但是当删除数据时,需要重新加载table里的数据.但是问题是datatable并没有直接的重新渲染,反而给数据累 ...
- 剑指offer编程题Java实现——面试题11数值的整数次方
题目: 实现函数double power(double base,int exponent),求base的exponent次方.不得使用库函数,同时不需要考虑大数问题. 解题思路:最一般的方法实现数值 ...
- Spring+SpringMVC+MyBatis+easyUI整合基础篇(五)讲一下maven
github地址,点这里. 项目效展示,点这里.账号:admin 密码:123456 下一篇文章开始,所有的项目源码都是与maven整合后的代码了,所以这一篇讲一讲maven. 1.简单介绍 我们看一 ...
- 从C#到TypeScript - Proxy
总目录 从C#到TypeScript - 类型 从C#到TypeScript - 高级类型 从C#到TypeScript - 变量 从C#到TypeScript - 接口 从C#到TypeScript ...
- javascript中加var和不加var的区别
Javascript是遵循ECMAScript标准下的一个产物,自然ECMAScript的标准其要遵循. 先来看下var关键字的定义和用法 var 语句用于声明变量. JavaScript 变量的创建 ...
- SQL SERVER 事务日志 解析
1 基本介绍 每个数据库都具有事务日志,用于记录所有事物以及每个事物对数据库所作的操作. 日志的记录形式需要根据数据库的恢复模式来确定,数据库恢复模式有三种: 完整模式,完全记录事物日志,需要定期进行 ...
- nginx配置之深入理解
继上一篇<debian+nginx配置初探--php环境.反向代理和负载均衡>成功之后,有点小兴奋,终于不用整lvs那么复杂来搞定负载,但还是有很多概念没弄清楚. 什么是CGI.FastC ...