如何使用Java中的Enum类
Java1.5 中出现了枚举类型。当一个值都在一个固定的范围内变化,那就可以使用 enum 类型来定义。比如说,一周有七天,一年有四季。
没有枚举类的时候,我们用常量来定义一组范围值的:
public static class Season {
public static final int SPRING = 1;
public static final int SUMMER = 2;
public static final int AUTUMN = 3;
public static final int WINTER = 4;
}
通过常量定义的方式有这样几个缺点:
类型不安全。如
Season类所示,程序执行过程中接收的是任意一个int类型的值,完全可能传入一个 1 到 4 之外的值,导致错误的出现。一致性差。int 枚举属于编译期常量,编译完成后,代码中引用的地方会直接将整数值写入。也就是说,该 Int 枚举被修改之后,所有引用它的程序都需要重新编译。
类型无指意性。Seaon 枚举值仅仅是一些无任何含义的整数值,调试期间仅仅是一些魔数。
定义一个 enum
《阿里巴巴Java开发手册(华山版)》中建议我们这样定义一个 enum 类:
【参考】枚举类名带上 Enum 后缀,枚举成员名称需要全大写,单词间用下划线隔开。
说明:枚举其实就是特殊的类,域成员均为常量,且构造方法被默认强制是私有。
正例:枚举名字为 ProcessStatusEnum 的成员名称:SUCCESS / UNKNOWN_REASON。
【推荐】如果变量值仅在一个固定范围内变化用 enum 类型来定义。
说明:如果存在名称之外的延伸属性应使用 enum 类型,下面正例中的数字就是延伸信息,表示一年中的第几个季节。
由此,我们可以定义一个季节的枚举类,如下所示:
public enum SeasonEnum {
SPRING(1), SUMMER(2), AUTUMN(3), WINTER(4);
private int seq;
SeasonEnum(int seq) {
this.seq = seq;
}
public int getSeq() {
return seq;
}
}
enum 类
使用 enum 定义的枚举类默认继承 java.lang.Enum :
public abstract class Enum<E extends Enum<E>>
implements Comparable<E>, Serializable {
...
}

变量
// enum 实例的名字
private final String name;
// 定义enum实例的顺序,从0开始计数
private final int ordinal;
方法
// 返回enum实例的名称,eg. SeasonEnum.SPRING.name() - output: SPRING
public final String name() { return name;}
// 返回enum实例的顺序,eg. SeasonEnum.SPRING.ordinal() - output: 0
public final int ordinal() { return ordinal;}
// enum实例 -> 字符串 eg. SeasonEnum.SPRING.toString() - output: SPRING
public String toString() { return name;}
// 比较是不是一个constant,即两个enum实例的顺序(oridnal)是否相同
public final int compareTo(E o) { ... return self.ordinal - other.ordinal; }
// 比较是不是同一个对象
public final boolean equals(Object other) { return this==other;}
// 返回声明枚举常量的类的类对象
public final Class<E> getDeclaringClass(){...}
// 返回指定name的enum实例
public static <T extends Enum<T>> T valueOf(Class<T> enumType,String name) {}
// values()是编译器产生的一个方法,API中没有,可以用来遍历
public static SeasonEnum getSeasonByOrdinal(int seq) {
for (SeasonEnum season: SeasonEnum.values()) {
if(season.getSeq() == seq) {
return season;
}
}
return null;
}
enum 的用法
用法一:定义常量
也就是最开始说的,enum 出现之后,用 enum 来代替常量类型。
public static class Season {
public static final int SPRING = 1;
public static final int SUMMER = 2;
public static final int AUTUMN = 3;
public static final int WINTER = 4;
}
public enum SeasonEnum {
SPRING, SUMMER, AUTUMN, WINTER;
}
用法二:switch
Java1.5 推出了 enum,Java1.6 支持在 switch 中使用 enum 类型。
public enum OperationUseSwitch {
PLUS, MINUS, TIMES, DIVIDE;
double apply(double x, double y) {
switch (this) {
case PLUS:
return x + y;
case MINUS:
return x - y;
case TIMES:
return x * y;
case DIVIDE:
return x / y;
}
// 如果this不属于上面四种操作符,抛出异常
throw new AssertionError("Unknown operation: " + this);
}
}
用法三:特定于常量的方法实现
特定于常量的方法实现指的是,在 enum 类中定义一个抽象方法,然后各个枚举常量需要实现这个方法。这样做的优点在于,相对于 switch 语句,抽象程度更高,每个 enum 实例都需要实现统一的方法,不会漏下。
public enum Operation {
PLUS {
double apply(double x, double y) {
return x + y;
}
},
MINUS {
double apply(double x, double y) {
return x - y;
}
},
TIMES {
double apply(double x, double y) {
return x * y;
}
},
DIVIDE {
double apply(double x, double y) {
return x / y;
}
};
abstract double apply(double x, double y);
}
用法四:实现接口
enum 类都隐式得继承自 java.lang.Enum,而 Java 只支持单继承,所有 enum 类不能再继承其它类,但是可以实现接口。比如用法三中将统一的方法抽象出来,就可以使用接口来实现:
public interface Behavior {
double apply(double x, double y);
}
public enum Operation implements Behavior{
PLUS {
public double apply(double x, double y) {
return x + y;
}
},
MINUS {
public double apply(double x, double y) {
return x - y;
}
},
TIMES {
public double apply(double x, double y) {
return x * y;
}
},
DIVIDE {
public double apply(double x, double y) {
return x / y;
}
};
}
用法五:覆盖 Enum 的方法
public class Test {
public enum Color {
RED("红色", 1), GREEN("绿色", 2), BLANK("白色", 3), YELLO("黄色", 4);
// 成员变量
private String name;
private int index;
// 构造方法
private Color(String name, int index) {
this.name = name;
this.index = index;
}
// 覆盖方法
@Override
public String toString() {
return this.index + "_" + this.name;
}
}
public static void main(String[] args) {
System.out.println(Color.RED.toString());
}
}
EnumSet 和 EnumMap
EnumSet 和 EnumMap 是两个为枚举而设计的集合。EnumSet保证集合中的元素不重复;EnumMap中的 key 是enum 类型,而 value 则可以是任意类型。
EnumMap
public class Herb {
public enum Type { ANNUAL, PERENNIAL, BIENNIAL }
private final String name;
private final Type type;
Herb(String name, Type type) {
this.name = name;
this.type = type;
}
@Override public String toString() {
return name;
}
}
public static void main(String[] args) {
Herb[] garden = { new Herb("Basil", Type.ANNUAL),
new Herb("Carroway", Type.BIENNIAL),
new Herb("Dill", Type.ANNUAL),
new Herb("Lavendar", Type.PERENNIAL),
new Herb("Parsley", Type.BIENNIAL),
new Herb("Rosemary", Type.PERENNIAL) };
// Using an EnumMap to associate data with an enum - Page 162
Map<Herb.Type, Set<Herb>> herbsByType = new EnumMap<Herb.Type, Set<Herb>>(
Herb.Type.class);
for (Herb.Type t : Herb.Type.values())
herbsByType.put(t, new HashSet<Herb>());
for (Herb h : garden)
herbsByType.get(h.type).add(h);
System.out.println(herbsByType);
}
EnumSet
EnumSet 是枚举类型的高性能 Set 实现,它要求放入它的枚举常量必须属于同一枚举类型。EnumSet 提供了许多工厂方法以便于初始化。
| 方法名称 | 描述 |
|---|---|
| allOf(Class element type) | 创建一个包含指定枚举类型中所有枚举成员的 EnumSet 对象 |
| complementOf(EnumSet s) | 创建一个与指定 EnumSet 对象 s 相同的枚举类型 EnumSet 对象, 并包含所有 s 中未包含的枚举成员 |
| copyOf(EnumSet s) | 创建一个与指定 EnumSet 对象 s 相同的枚举类型 EnumSet 对象, 并与 s 包含相同的枚举成员 |
| noneOf(<Class elementType) | 创建指定枚举类型的空 EnumSet 对象 |
| of(E first,e...rest) | 创建包含指定枚举成员的 EnumSet 对象 |
| range(E from ,E to) | 创建一个 EnumSet 对象,该对象包含了 from 到 to 之间的所有枚 举成员 |
EnumSet 作为 Set 接口实现,它支持对包含的枚举常量的遍历。
for(Operation op:EnumSet.range(Operation.PLUS,Operation.MULTIPLY)) {
doSomeThing(op);
}
参考文献
Java枚举 —— 很少被使用,或许是因为真正了解它的人太少了
Java枚举(enum)详解:Java声明枚举类型、枚举(enum)类、EnumMap 与 EnumSet
如何使用Java中的Enum类的更多相关文章
- 深入掌握Java中的enum
对于要在程序中要表示有限种类的某事物,一般我们可以采用两种方式,一是使用:public static final String 常量:二是使用enum来表示.一般而言前者简单,但是不能够很好的提供更多 ...
- 带有静态方法的类(java中的math类)
带有静态方法的类通常(虽然不一定是这样)不打算被初始化. 可以用私有构造函数来限制非抽象类被初始化. 例如,java中的math类.它让构造函数标记为私有,所以你无法创建Math的实例.但Math类却 ...
- java中的File类
File类 java中的File类其实和文件并没有多大关系,它更像一个对文件路径描述的类.它即可以代表某个路径下的特定文件,也可以用来表示该路径的下的所有文件,所以我们不要被它的表象所迷惑.对文件的真 ...
- Java基础(43):Java中的Object类与其方法(转)
Object类 java.lang.Object java.lang包在使用的时候无需显示导入,编译时由编译器自动导入. Object类是类层次结构的根,Java中所有的类从根本上都继承自这个类. O ...
- java中基于TaskEngine类封装实现定时任务
主要包括如下几个类: 文章标题:java中基于TaskEngine类封装实现定时任务 文章地址: http://blog.csdn.net/5iasp/article/details/10950529 ...
- Java中的Unsafe类111
1.Unsafe类介绍 Unsafe类是在sun.misc包下,不属于Java标准.但是很多Java的基础类库,包括一些被广泛使用的高性能开发库都是基于Unsafe类开发的,比如Netty.Hadoo ...
- Java中遍历实体类(处理MongoDB)
在实际过程中,经常要将实体类进行封装,尤其是处理数据库的过程中:因此,对于遍历实体类能够与数据库中的一行数据对应起来. 我是使用的环境是Spring boot,访问的数据库时MongoDB 实体类遍历 ...
- java中遍历实体类,获取属性名和属性值
方式一(实体类): //java中遍历实体类,获取属性名和属性值 public static void testReflect(Object model) throws Exception{ for ...
- Java中的BigDecimal类精度问题
bigdecimal 能保证精度的原理是:BigDecimal的解决方案就是,不使用二进制,而是使用十进制(BigInteger)+小数点位置(scale)来表示小数,就是把所有的小数变成整数,记录小 ...
随机推荐
- docker 学习(四)
1.Dockerfile简介 1)什么是Dockerfile Dockerfile是一个包含用于组合映像的命令的文本文档.可以使用在命令行中调用任何命令. Docker通过读取Dockerfile中的 ...
- Java堆内存是线程共享的!面试官:你确定吗?
Java作为一种面向对象的,跨平台语言,其对象.内存等一直是比较难的知识点,所以,即使是一个Java的初学者,也一定或多或少的对JVM有一些了解.可以说,关于JVM的相关知识,基本是每个Java开发者 ...
- 前端解决跨域问题的终极武器——Nginx反向代理
提到代理,分为:正向代理和反向代理. 正向代理:就是你访问不了Google,但是国外有个VPN可以访问Google,你访问VPN后叫它访问Google,然后把数据传给你. 正向代理隐藏了真实的客户端. ...
- CJSON的封装API
为了更方便使用C的JSON库,对其进行了一层封装. H文件: #ifndef __JSONHELPER__ #define __JSONHELPER__ #ifdef __cplusplus exte ...
- 爬虫之requestsku
想用selenium实现B站自动登录已经点赞等功能,看到如何解决滑动解锁有关爬虫的内容,便开始学习爬虫,没过多久又想把记录自己生活的网站做起来,朋友便推荐了layui框架倒腾了一晚上自我觉得是做后台系 ...
- Linux系统是什么?亲身自学经历分享
我是数字媒体专业学生,第一次接触LINUX的时候,是大一C语言课程里看到的,书上讲了C语言的发展历史.说到C语言的起源,就离不开UNIX系统.在20世纪60年代,贝尔实验室的研究员Ken Thomps ...
- Vue2.0 【第二季】第8节 Component 父子组件关系
目录 Vue2.0 [第二季]第8节 Component 父子组件关系 第8节 Component 父子组件关系 一.构造器外部写局部注册组件 二.父子组件的嵌套 Vue2.0 [第二季]第8节 Co ...
- markdown从入门到放弃word和PDF
Markdown是一个「轻量级」的「标记语言」. 淡定!!!我知道很多"编外人员"看到这句话之后已经没有兴趣再看下去了. 但是请不要关掉这个页面!!! Markdown很简单!!! ...
- python中那些让开发事半功倍的模块
1. Map Map会将一个函数映射到一个输入列表的所有元素上 ex: 有一个列表: [1,2,3,4,5,6], 现在要求把列表每个元素乘以10 如果你还不知道Map,那你可能会这样做: list1 ...
- 关于Idea中不能使用Scanner在console
遇到了麻烦,在Idea中使用@Test运行程序时,scanner在控制台无法输入,然后来回折腾... 创建了一个新的类里面含有main方法,可以完美运行scanner: 重新回来,发现还是不行, 创建 ...