全面解读Java中的枚举类型enum的使用
这篇文章主要介绍了Java中的枚举类型enum的使用,开始之前先讲解了枚举的用处,然后还举了枚举在操作数据库时的实例,需要的朋友可以参考下
关于枚举
大多数地方写的枚举都是给一个枚举然后例子就开始switch,可是我想说,我代码里头来源的数据不太可能就是枚举,通常是字符串或数字,比如一个SQL我解析后首先判定SQL类型,通过截取SQL的token,截取出来可能是SELECT、DELETE、UPDATE、INSERT、ALTER等等,但是都是字符串,此时我想用枚举就不行了,我要将字符串转换成枚举怎么转呢,类似的情况还有从数据库取出数据根据一些类型做判定,从页面传入数据,根据不同的类型做不同的操作,但是都是字符串,不是枚举,悲剧的是我很少看到有人写到这个东西;所以我把它写下来,希望有人能用到。
首先为什么要用枚举?我们在什么时候用枚举比较好,用枚举有啥优势?
我认为哈,当你在一些一个范畴类,并可列举,不变化的类型,用以指导程序向不同的地方路由,用枚举是较好的选择;
听起来有点绕,不过有个例子也许可以明白,例如:
我们可以列举下日常工作日所做的事情:
上班、开会、吃饭、睡觉等
我们可以列举医院五官科需要检查人的部位:
眼睛、鼻子、耳朵、嘴巴等
这些都是可以被列举的,且每种事情我们要用不同的方式去做;
当然你可以说:
1、可以用动态方法分派,通过配置文件或annotation;
2、可以使用常量来达到类似的效果;
3、直接通过字符串的equals来表达,用if else来表达
如果用配置加方法分派来做,是灵活,便于修改;但是如果在很多不经常修改的参数上,我们用这中方式往往增加配置的负担,并且当你需要看系统逻辑的时候,需要需要一遍看配置一遍看代码;不过,如果参数是可动态变换的信息,用配置是正确的选择;
而常量的使用,通常在switch case的时候都是数字,字符串在java中是不能做switch case的,使用常量的目的比case 1、case 2 …这种增加了可读性;但是字符串数据也麻烦,除非再映射一次,那没那个必要,其实枚举也差不多是帮你映射了一次,只是它将代码封装了而已吧了,既然他弄好了,而且语法上支持,干嘛不用呢!其次,常量虽然增加了可读性,不过他没有范畴和管理类型的概念,即一个枚举的定义会定义个范畴,可以很好的将这个范围所需要的东西列举出来,而常量通常是些自己定义的一些池,放在一些公共类中或随机定义,都是比较零散的,并且枚举在switch的时候就明确定义好了就在锁列举的范围内case,既可以控制好系统,增加可读性,并且可以随时查看这个范畴的枚举信息到底有那些,达到类似看配置文件的作用;不过还是回到那句话,如果参数是可变的,那么就不适合做枚举,枚举是一定是可列举的,或者说当前系统考虑范围是可以被枚举的,例如上面的医院五官科,可能还有很多没有列举到,但是当前医院只处理几个部位,不处理其他的,就是这个道理;什么是可变的呢,例如URL参数来分派到对应方法,不可能大家加一段逻辑就去加一个枚举,加一个case,此时用【配置+动态方法分派】更好,当然配置可以用文件或annotation而已。
还有最土的就是,通过字符串equals,用if else来实现,呵呵,这个并没有什么不好,只是这个写比较零散,其次,字符串匹配的equals每次匹配都需要对比每个字符,如果你的代码中大量循环,性能并不是很好,其余的看看上面的描述就更加清楚了;
其次,枚举提供一种类型管理的组件,让面向对象的体系更加完善,使得一些类型的管理既可配置化,并可以管理,在使用枚举的地方都可以沿着枚举的定义找到那些有处理过,那些没处理过,而上述几种很难做到;例如,数据库的操作类型定义了10种,那么再判定的过程中就可以讲枚举像配置文件一样看待,而又非常简单的来管理。
最后,枚举绝对是单例的,对比的性能和数字性能相当,既可以得到可读性,也可以得到性能。
enum类型的基本使用
有了这样的理论基础,我们下面就来看Java中的enum枚举类型:
1、可以在enum中添加变量和方法
先来看一段代码示例:
public enum State {
Normal("正常态", 1), Update("已更新", 2), Deleted("已删除", 3), Fired("已屏蔽", 4);
// 成员变量
private String name;
private int index;
// 构造方法,注意:构造方法不能为public,因为enum并不可以被实例化
private State(String name, int index) {
this.name = name;
this.index = index;
}
// 普通方法
public static String getName(int index) {
for (State c : State .values()) {
if (c.getIndex() == index) {
return c.name;
}
}
return null;
}
// get set 方法
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getIndex() {
return index;
}
public void setIndex(int index) {
this.index = index;
}
}
从上面的代码中我们可以看到,定义完枚举值,然后在其后面加上分号,接着就可以定义其他的变量、方法了。另外需要特别说明的是,enum中的构造方法不可以用public标识,这样做是为了防止用户实例化enum。
2、可以用来定义常量
先来回顾一下Java中如何定义常量吧,看下面一段代码:
public static final int normalState = 1;
private static final int updateState = 2;
下面我们还可以用enum枚举来代替上面的常量定义,代码如下:
public enum State {
Normal, Update, Deleted, Fired
}
在Java中用enum来定义常量在语法上没有什么优势,但是enum枚举类型可以提供更多的操作功能。
3、在enum中实现接口
先来看下面一段代码:
public interface ICanReadState {
void read();
String getState();
}
public enum State implements ICanReadState {
Normal("正常态", 1), Update("已更新", 2), Deleted("已删除", 3), Fired("已屏蔽", 4);
private String name;
private int index;
private State(String name, int index) {
this.name = name;
this.index = index;
}
// 接口方法1
@Override
public String getState() {
return this.name;
}
// 接口方法2
@Override
public void read() {
System.out.println(this.index + ":" + this.name);
}
}
和一般的类中使用接口一样,enum枚举中同样可以继承接口,并实现接口中的所有方法,这样做的好处在于可以更方便地对枚举中的值进行排序、比较等操作,封装性更好。
实例
我们先定义个简单枚举(这里只是个例子,就简单定义3个变量了):
public enum SqlTypeEnum {
INSERT ,
UPDATE ,
DELETE ,
SELECT
}
此时解析SQL后,获取出来一个token,我们要获取这个token的枚举怎么获取呢?
这样获取:
String token = "select";
SqlTypeEnum sqlTypeEnum = SqlTypeEnum.valueOf(token.toUpperCase());
如果没获取到,java会抛出一个异常哦:IllegalArgumentException No enum const class SqlTypeEnum.XXX
我做大写处理的原因是因为枚举也是大写的(当然如果你的枚举是小写的,那你就小写,不过混写比较麻烦哈),其实valueOf就是调用了枚举的底层映射:
201642785504527.jpg (575×287)
调用的时候会调用这个方法:
201642785619095.jpg (491×205)
所以内部也是一个HashMap,呵呵!
拿到这个信息后,就可以做想要的操作了:
switch(sqlTypeEnum) {
case INSERT:处理insert逻辑;break;
case DELETE:处理delete逻辑;break;
....
}
OK,有些时候可能我们不想直接用INSERT、UPDATE这样的字符串在交互中使用,因为很多时候命名规范的要求;
例如定义一些用户操作类型:
1、保存用户信息
2、通过ID获取用户基本信息
3、获取用户列表
4、通过ID删除用户信息
等等
我们可能定义枚举会定义为:
public enum UserOptionEnum {
SAVE_USER,
GET_USER_BY_ID,
GET_USER_LIST,
DELETE_USER_BY_ID
}
但是系统的方法和一些关键字的配置,通常会写成:
saveUser、getUserById、getUserById、deleteUserById
当然各自有各自的规则,不过中间这层映射,你不想做,就一方面妥协,要么枚举名称全部换掉,貌似挺奇怪的,要么方法名称全部换掉,更加奇怪,要么自己做映射,可以,稍微麻烦点,其实也不麻烦?
我们首先写个将枚举下划线风格的数据转换为驼峰的方法,放在一个StringUtils里面:
public static String convertDbStyleToJavaStyle(String dbStyleString , boolean firstUpper) {
dbStyleString = dbStyleString.toLowerCase();
String []tokens = dbStyleString.split("_");
StringBuilder stringBuilder = new StringBuilder(128);
int length = 0;
for(String token : tokens) {
if(StringUtils.isNotBlank(token)) {
if(length == 0 && !firstUpper) {
stringBuilder.append(token);
}else {
char c = token.charAt(0);
if(c >= 'a' || c <= 'z') c = (char)(c - 32);
stringBuilder.append(c);
stringBuilder.append(token.substring(1));
}
}
++length;
}
return stringBuilder.toString();
}
重载一个方法:
public static String convertDbStyleToJavaLocalStyle(String dbStyleString) {
return convertDbStyleToJavaStyle(dbStyleString , false);
}
然后定义枚举:
public enum UserOptionEnum {
SAVE_USER,
GET_USER_BY_ID,
GET_USER_LIST,
DELETE_USER_BY_ID;
private final static Map<String , UserOptionEnum> ENUM_MAP = new HashMap<String, UserOptionEnum>(64);
static {
for(UserOptionEnum v : values()) {
ENUM_MAP.put(v.toString() , v);
}
}
public staticUserOptionEnum fromString(String v) {
UserOptionEnum userOptionEnum = ENUM_MAP.get(v);
return userOptionEnum == null ? DEFAULT :userOptionEnum;
}
public String toString() {
String stringValue = super.toString();
return StringUtil.convertDbStyleToJavaLocalStyle(stringValue);
}
}
OK,这样传递一个event参数让如果是:saveUser,此时就用:
String event = "saveUser";//假如这里得到参数
UserOptionEnum enum = UserOptionEnum.fromString(event);
其实就是自己做了一个hashMap,我这加了一个fromString,因为枚举有一些限制,有些方法不让你覆盖,比如valueOf方法就是这样。
其实没啥好讲的了,非要说,再说说枚举加一些自定义变量吧,其实枚举除了是单例的外,其余的和普通类也相似,它也可以有构造方法,只是默认情况下不是而已,也可以提供自定义的变量,然后获取set、get方法,但是如果有set的话,线程不是安全的哦,要注意这点;所以一般是构造方法就写好了:
public enum SqlTypeEnum {
INSERT("insert into"),
DELETE("delete from")
......省略;
private String name;//定义自定义的变量
private SqlTypeEnum(String name) {
this.name = name;
}
public String getName() {
return name;
}
public String toString() {
return name + " 我靠";//重写toString方法
}
//一般不推荐
public void setName(String name) {
this.name = name;
}
}
调用下:
SqlTypeEnum sqlTypeEnum = SqlTypeEnum.valueOf("INSERT");
System.out.println(sqlTypeEnum);
System.out.println(sqlTypeEnum.getName());
不推荐也调用下:
sqlTypeEnum.setName("我靠");
在另一个线程:
SqlTypeEnum sqlTypeEnum = SqlTypeEnum.valueOf("INSERT");
System.out.println(sqlTypeEnum);
System.out.println(sqlTypeEnum.getName());
发现结果被改了,呵呵!
全面解读Java中的枚举类型enum的使用的更多相关文章
- Java中的枚举类型详解
枚举类型介绍 枚举类型(Enumerated Type) 很早就出现在编程语言中,它被用来将一组类似的值包含到一种类型当中.而这种枚举类型的名称则会被定义成独一无二的类型描述符,在这一点上和常量的定义 ...
- C# 中的枚举类型 enum (属于值类型)
原文 C# 中的枚举类型 enum (属于值类型) C# 支持两种特殊的值类型:枚举和结构. 声明枚举:声明时要声明所有可能的值. using System; using System.Collect ...
- Java基础之枚举类型Enum的使用
Java基础之枚举类型Enum的使用 定义 public enum AccruedCleanEnum { SPREAD("1","发票"),OTHER(&quo ...
- 浅谈java中的枚举类型(转)
用法一:常量 在JDK1.5 之前,我们定义常量都是: public static fianl.... .现在好了,有了枚举,可以把相关的常量分组到一个枚举类型里,而且枚举提供了比常量更多的方法. p ...
- C#中的枚举类型enum用法
定义一个简单的枚举类型: enum Days {Sat, Sun, Mon, Tue, Wed, Thu, Fri}; //这时候 Days.Sat = 0 ,后面依 ...
- java中的枚举类型
枚举类型是那些字段由一组固定常量组成的类型.常见的例子有:东南西北四个方向,星期几等. 所有枚举类型都隐式继承java.lang.Enum类型,因为java不支持多重继承,所以枚举不能继承其他任何类. ...
- java中的枚举类enum
enum SeasonEnum {//枚举类: 本类规定了SeasonEnum(季节)类只能有四个对象SPRING,SUMMER,AUMUTN,WINTER //创建枚举类的的四个对象SPRING,S ...
- Java中自定义枚举(Enum)项的值,可设置为指定的值
一.代码 package base.lang; /** * ClassName: StateEnum * @Description: TODO * @author fuming * @date 20 ...
- 【转】java枚举类型enum的使用
原文网址:http://blog.csdn.net/wgw335363240/article/details/6359614 java 枚举类型enum 的使用 最近跟同事讨论问题的时候,突然同事提到 ...
随机推荐
- Android程序能够构建和运行,但是报以下报错,为什么?
安卓程序写完之后能够构建和运行,但是会报以下的错误.不知道原因为何?求大神解答. 网上说的是混淆编译的原因,不过程序没有开启混淆编译. Error:warning: Ignoring InnerCla ...
- 找出 alter system kill session ‘sid,serial#’ kill 掉的数据库会话对应进程
当我们使用alter system kill session ‘sid,serial#’ 在数据库中kill掉某个会话的时候,如果你观察仔细会发现v$session.paddr发生了改变,从而是的不能 ...
- SpringCloud学习笔记(13)----Spring Cloud Netflix之Hystrix断路器的隔离策略
说明 : 1.Hystrix通过舱壁模式来隔离限制依赖的并发量和阻塞扩散 2. Hystrix提供了两种隔离策略:线程池(THREAD)和信号量隔离SEMAPHORE). 1. 线程池隔离(默认策略模 ...
- ZBrush功能特性之法线贴图
ZMapper是ZBrush2.0推出的免费法线贴图插件.使用ZBrush革命性的多级别精度和新型的照明-快速光线跟踪器,ZMapper可以在几秒内产生适用于任何游戏引擎的法线贴图,不过3.5版本以后 ...
- EasyUI Combotree只选择叶子节点
EasyUI Combotree的方法拓展自Combo和Tree.而Tree有一个onBeforSelect事件来帮助我们实现只选择叶子节点的功能. Tree事件需要 'node' 参数,它包括下列属 ...
- c traps and pitfalls reading note(1)
1. 一直知道char *p = 'a';这样写是错误的,但是为什么是错的,没想过,今天看书解惑. p指向一个字符,但是在c中,''引起来的一个字符代表一个整数,这样指针能不报错.o(^▽^)o 2. ...
- 紫书 例题8-8 UVa 1471 (用set实现动态二分)
设切割的区间为(j, i), 注意两边都是开区间. 然后可以预处理出以i为起点的最长连续递增的长度和以j为终点的最长连续递增的长度. 大致思路就是枚举i,右边这一侧的最优值就知道了, 然后这道题的关键 ...
- 个人创业了,做了个网站和App,www.91tianwu.com
大家好! 很久没有写文章了,响应党和政府号召,创业了.此文为了推广我的网站而写,希望有兴趣的看看. 我做了添物网,地址:http://www.91tianwu.com. 主要做购物导航推荐,目前集中在 ...
- [MST] Create Dynamic Types and use Type Composition to Extract Common Functionality
Since MST offers a runtime type system, it can create and compose types on the fly, making it possib ...
- iOS设计模式之NSNotificationCenter 消息中心
消息中心模式和KVO模式有点相似,差别在于.KVO 模式是意图在于监听摸一个相应的值的变化.而去出发一个方法相应的动作.而消息中心在于,广播.它就像一个广播基站,发送一条消息,在全部的加入监听的地方 ...