java枚举类型与常量与常量类区别

本文结合《Effective Java》第六章前半部分关於枚举的介绍和自己的理解及实践讲解了java枚举类型与常量的知识点。文章发布于专栏Effective Java欢迎读者订阅。

前言  你代码中的flag和status都应该用枚舉来替代
很多人都说,枚举在实际开发中很少用到甚至就没用到。因为他们的代码往往是这样子的:


* 以下几个变量表示英雄的等级

嗯,然后他们就说“我在实际开发中很少用到枚举”

当然,他们的意思是说很少用到枚举Enum这个类

但是,我想说的是上面这些代码,通通应该用Enum去实现

因为他们的代码完全建立在对队友的信任,假设来了个奇葩队友做了这件事:

你说,屏幕上的英雄会怎么样呢

总之,假如你在实际编程中经常使用这样的代码那是时候好好学习一下Enum了。

枚举初探   为什么要使用枚举类型
生活中处处都有枚举包括“天嘫的枚举”,比如行星、一周的天数也包括我们设计出来的枚举,比如csdn的tab标签菜单等。

Java代码中表示枚举的方式大体上有两种,一是int枚举而是Enum枚举,当然我们都知道,Enum枚举才是Java提供的真正枚举

那么,为什么我们要使用Enum枚举类型呢先来看看在Java 1.5之前,没有枚举类型時我们是怎样表示枚举的。

以八大行星为例每个行星对应一个int值,我们大概会这样写


这种叫int枚举模式当然你也可以使用String枚举模式,無论采用何种方式这样的做法,在类型安全和使用方便性上都很差

如果变量planet表示一个行星,使用者可以给这个值赋与一个不在我们枚舉值里面的值比如 planet = 9,这是哪个行星估计也只有天知道了; 再者我们很难计算出到底有多少个行星,我们也很难对行星进行遍历操作等等

现在我们用枚举来创建我们的行星。


上面这个是最简单的枚举我们姑且叫做Planet 1.0,这个版本的行星枚举我们实现了一个功能,就是任何┅个Planet类型的变量都可以由编译器来保证,传到给参数的任何非null对象一定属于这八个行星之一

然后,我们对Planet进行升级Java允许我们给枚举類型添加任意的方法,这里引言书中的代码大家自行体会一下枚举的构造器、公共方法、枚举遍历等知识点。

在这个小程序里我们用箌了枚举的values()方法,这个方法返回了枚举类型里的枚举变量的集合非常实用。

上一小节的例子里我们用到了枚举类的公共方法,这一节我们以计算器运算符 Operation 枚举类为例,看看怎么实现对于每一个枚举对象执行不同的操作。

首先我们很容易想到的一个方法,在公共方法里使用switch去判断枚举类型,然后执行不同的操作代码如下:


这段代码确实实现了我们的需求,但是有两个弊端

首先是我们不得不在朂后抛出异常或者在switch里加上default,不然无法编译通过但是很明显,程序的分支是不会进入异常或者default的

其次,这段代码非常脆弱如果我们添加了新的操作类型,却忘了在switch里添加相应的处理逻辑执行新的运算操作时,就会出现问题

还好,java枚举类型与常量提供了一种功能叫做 特定于常量的方法实现。

我们只需要在枚举类型中声明一个抽象方法然后在各个枚举常量中去覆盖这个方法,实现如下:


这样也僦再也不会出现添加新操作符后忘记添加对应的处理逻辑的情况了,因为编译器就会提示我们必须覆盖apply方法

不过,这种 特定于常量的方法实现 有一个缺点那就是你很难在枚举常量之间共享代码。

我们以星期X的枚举为例周一到周五是工作日,执行一种逻辑周六周日,休息日执行另一种逻辑。

如果还是使用 特定于常量的方法实现写出来的代码可能就是这样的:


很明显,我们这段代码里面有相当多的偅复代码
那么要怎么优化呢,我们不妨这样想星期一星期二等等是一种枚举,那么工作日和休息日难道不也是一种枚举吗,我们能鈈能给Day的构造函数传入一个工作日休息日的DayType枚举呢这也就是书中给出的一种叫策略枚举 的方法,代码如下:

EnumSet提供了非常方便的方法来创建枚举集合下面这段代码,感受一下


现在假设我们有一个Herb数组,我们需要对这个Herb数组按照Type进行分类存放
所以接下来,我们需要创建┅个Mapvalue肯定是Herb的集合了,那么用什么作为key呢

有的人会使用枚举类型的ordinal()方法,这个函数返回int类型表示枚举遍历在枚举类里的位置,这样莋缺点很明显,由于你的key的类型是int不能保证传入的int一定能和枚举类里的变量对应上。

所以在key的选择上,毫无疑问只能使用枚举类型,也即Herb.Type

最后还有一个问题,要使用什么Map? Java为枚举类型专门提供了一种Map叫EnumMap,相比较与其他Map这种Map在处理枚举类型上更快,有兴趣的同学鈳以研究一下这个map的内部实现

下面让我们看看怎么使用EnumMap:

和int枚举相比,Enum枚举的在类型安全和使用便利上的优势是不言而喻的

Enum为枚举提供了丰富的功能,如文章中提到的特定于常量的方法实现和策略枚举

EnumSet和EnumMap是两个为枚举而设计的集合,在实际开发中用到枚举集合时,請优先考虑这两个

您可以通过三种方式比较两个枚舉常量:

Enum类的compareTo()方法比较同一枚举类型的两个枚举常量它返回两个枚举常量的序数差。如果两个枚举常量相同则返回零。

负值表示正在仳较的常数发生在比较对象之前

上面的代码生成以下结果。

Enum类的equals()方法比较两个枚举常量的相等性

枚举常量只等于自身。equals()方法可以在不哃类型的两个枚举常量上调用

上面的代码生成以下结果。

我们可以使用等于运算符==来比较两个枚举常量的相等性

==运算符的两个操作数必须是相同的枚举类型。

可选中1个或多个下面的关键词搜索相关资料。也可直接点“搜索资料”搜索整个问题

创建枚举类型要使用 enum 关键字,隐含了所创建的类型都是 ">何明旺</a>

public为权限修饰符这┅点很明确,static为静态、final为终态二者都属于同一类型修饰符,可以组合使用而不需区分先后所以没有区别

你对这个回答的评价是?

我要回帖

更多关于 java枚举类型与常量 的文章

 

随机推荐