- ubuntu12.04环境下使用kvm ioctl接口实现最简单的虚拟机
- Ubuntu 通过无线网络安装Ubuntu Server启动系统后连接无线网络的方法
- 在Ubuntu上搭建网桥的方法
- ubuntu 虚拟机上网方式及相关配置详解
CFSDN坚持开源创造价值,我们致力于搭建一个资源共享平台,让每一个IT人在这里找到属于你的精彩世界.
这篇CFSDN的博客文章Java枚举的使用方法详解由作者收集整理,如果你对这篇文章有兴趣,记得点赞哟.
Java枚举的使用方法详解 。
前言 你代码中的flag和status,都应该用枚举来替代 。
很多人都说,枚举在实际开发中很少用到,甚至就没用到。因为,他们的代码往往是这样子的:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
public
class
Constant {
/*
* 以下几个变量表示英雄的状态
*/
public final static int STATUS_WALKING = 0;//走
public final static int STATUS_RUNNINGING = 1;//跑
public final static int STATUS_ATTACKING = 2;//攻击
public final static int STATUS_DEFENDING = 3;//防御
public final static int STATUS_DEAD = 4;//挂了
/*
* 以下几个变量表示英雄的等级
*/
//此处略去N行代码
}
|
然后,他们是这样使用这个类的:
1
|
hero.setStatus(Contant.STATUS_ATTACKING);
|
嗯,然后他们就说,“我在实际开发中很少用到枚举” 。
当然,他们的意思是说很少用到枚举Enum这个类.
但是,我想说的是,上面这些代码,通通应该用Enum去实现.
为什么?
因为他们的代码完全建立在对队友的信任,假设来了个奇葩队友,做了这件事:
1
|
hero.setStatus(
666
);
|
你说,屏幕上的英雄会怎么样呢?
总之,假如你在实际编程中经常使用这样的代码,那是时候好好学习一下Enum了.
枚举初探 为什么要使用枚举类型 。
生活中处处都有枚举,包括“天然的枚举”,比如行星、一周的天数,也包括我们设计出来的枚举,比如csdn的tab标签,菜单等.
Java代码中表示枚举的方式,大体上有两种,一是int枚举,而是Enum枚举,当然,我们都知道,Enum枚举才是Java提供的真正枚举.
那么,为什么我们要使用Enum枚举类型呢?先来看看在Java 1.5之前,没有枚举类型时,我们是怎样表示枚举的.
以八大行星为例,每个行星对应一个int值,我们大概会这样写 。
1
2
3
4
5
6
7
8
9
10
|
public
class
PlanetWithoutEnum {
public
static
final
int
PLANET_MERCURY =
0
;
public
static
final
int
PLANET_VENUS =
1
;
public
static
final
int
PLANET_EARTH =
2
;
public
static
final
int
PLANET_MARS =
3
;
public
static
final
int
PLANET_JUPITER =
4
;
public
static
final
int
PLANET_SATURN =
5
;
public
static
final
int
PLANET_URANUS =
6
;
public
static
final
int
PLANET_NEPTUNE =
7
;
}
|
这种叫int枚举模式,当然你也可以使用String枚举模式,无论采用何种方式,这样的做法,在类型安全和使用方便性上都很差。 如果变量planet表示一个行星,使用者可以给这个值赋与一个不在我们枚举值里面的值,比如 planet = 9,这是哪个行星估计也只有天知道了; 再者,我们很难计算出到底有多少个行星,我们也很难对行星进行遍历操作等等.
现在我们用枚举来创建我们的行星.
1
2
3
|
public
enum
Planet {
MERCURY, VENUS, EARTH, MARS, JUPITER, SATURN, URANUS, NEPTUNE;
}
|
上面这个是最简单的枚举,我们姑且叫做Planet 1.0,这个版本的行星枚举,我们实现了一个功能,就是任何一个Planet类型的变量,都可以由编译器来保证,传到给参数的任何非null对象一定属于这八个行星之一.
然后,我们对Planet进行升级,Java允许我们给枚举类型添加任意的方法,这里引言书中的代码,大家自行体会一下枚举的构造器、公共方法、枚举遍历等知识点.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
|
public
enum
Planet {
MERCURY(
3
.302e+
23
,
2
.439e6),
VENUS(
4
.869e+
24
,
6
.052e6),
EARTH(
5
.975e+
24
,
6
.378e6),
MARS(
6
.419e+
23
,
3
.393e6),
JUPITER(
1
.899e+
27
,
7
.149e7),
SATURN(
5
.685e+
26
,
6
.027e7),
URANUS(
8
.683e+
25
,
2
.556e7),
NEPTUNE(
1
.024e+
26
,
2
.477e7);
private
final
double
mass;
// In kilograms
private
final
double
radius;
// In meters
private
final
double
surfaceGravity;
// In m / s^2
// Universal gravitational constant in m^3 / kg s^2
private
static
final
double
G =
6
.67300E-
11
;
// Constructor
Planet(
double
mass,
double
radius) {
this
.mass = mass;
this
.radius = radius;
surfaceGravity = G * mass / (radius * radius);
}
public
double
mass() {
return
mass;
}
public
double
radius() {
return
radius;
}
public
double
surfaceGravity() {
return
surfaceGravity;
}
public
double
surfaceWeight(
double
mass) {
return
mass * surfaceGravity;
// F = ma
}
}
|
1
2
3
4
5
6
7
8
9
10
11
12
|
//注:这里对书中的代码做了微调
public
class
WeightTable {
public
static
void
main(String[] args) {
printfWeightOnAllPlanets(8d);
}
public
static
void
printfWeightOnAllPlanets(
double
earthWeight) {
double
mass = earthWeight / Planet.EARTH.surfaceGravity();
for
(Planet p : Planet.values())
System.out.printf(
"Weight on %s is %f%n"
, p, p.surfaceWeight(mass));
}
}
|
运行WeightTable,打印结果如下:
1
2
3
4
5
6
7
8
|
Weight on MERCURY is
3.023254
Weight on VENUS is
7.240408
Weight on EARTH is
8.000000
Weight on MARS is
3.036832
Weight on JUPITER is
20.237436
Weight on SATURN is
8.524113
Weight on URANUS is
7.238844
Weight on NEPTUNE is
9.090108
|
在这个小程序里,我们用到了枚举的values()方法,这个方法返回了枚举类型里的枚举变量的集合,非常实用.
枚举进阶 计算器运算符枚举类 。
上一小节的例子里,我们用到了枚举类的公共方法,这一节,我们以计算器运算符 Operation 枚举类为例,看看怎么实现对于 。
每一个枚举对象,执行不同的操作.
首先,我们很容易想到的一个方法,在公共方法里,使用switch去判断枚举类型,然后执行不同的操作,代码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
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
);
}
}
|
这段代码确实实现了我们的需求,但是有两个弊端.
首先是我们不得不在最后抛出异常或者在switch里加上default,不然无法编译通过,但是很明显,程序的分支是不会进入异常或者default的.
其次,这段代码非常脆弱,如果我们添加了新的操作类型,却忘了在switch里添加相应的处理逻辑,执行新的运算操作时,就会出现问题.
还好,Java枚举提供了一种功能,叫做 特定于常量的方法实现.
我们只需要在枚举类型中声明一个抽象方法,然后在各个枚举常量中去覆盖这个方法,实现如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
|
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);
}
|
这样,也就再也不会出现添加新操作符后忘记添加对应的处理逻辑的情况了,因为编译器就会提示我们必须覆盖apply方法.
不过,这种 特定于常量的方法实现 有一个缺点,那就是你很难在枚举常量之间共享代码.
我们以星期X的枚举为例,周一到周五是工作日,执行一种逻辑,周六周日,休息日,执行另一种逻辑.
如果还是使用 特定于常量的方法实现,写出来的代码可能就是这样的:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
|
public
enum
DayUseAbstractMethod {
MONDAY {
@Override
void
apply() {
dealWithWeekDays();
//伪代码
}
},
TUESDAY {
@Override
void
apply() {
dealWithWeekDays();
//伪代码
}
},
WEDNESDAY {
@Override
void
apply() {
dealWithWeekDays();
//伪代码
}
},
THURSDAY {
@Override
void
apply() {
dealWithWeekDays();
//伪代码
}
},
FRIDAY {
@Override
void
apply() {
dealWithWeekDays();
//伪代码
}
},
SATURDAY {
@Override
void
apply() {
dealWithWeekEnds();
//伪代码
}
},
SUNDAY {
@Override
void
apply() {
dealWithWeekEnds();
//伪代码
}
};
abstract
void
apply();
}
|
很明显,我们这段代码里面有相当多的重复代码.
那么要怎么优化呢,我们不妨这样想,星期一星期二等等是一种枚举,那么工作日和休息日,难道不也是一种枚举吗,我们能不能给Day的构造函数传入一个工作日休息日的DayType枚举呢?这也就是书中给出的一种叫策略枚举 的方法,代码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
|
public
enum
Day {
MONDAY(DayType.WEEKDAY), TUESDAY(DayType.WEEKDAY), WEDNESDAY(
DayType.WEEKDAY), THURSDAY(DayType.WEEKDAY), FRIDAY(DayType.WEEKDAY), SATURDAY(
DayType.WEEKDAY), SUNDAY(DayType.WEEKDAY);
private
final
DayType dayType;
Day(DayType daytype) {
this
.dayType = daytype;
}
void
apply() {
dayType.apply();
}
private
enum
DayType {
WEEKDAY {
@Override
void
apply() {
System.out.println(
"hi, weekday"
);
}
},
WEEKEND {
@Override
void
apply() {
System.out.println(
"hi, weekend"
);
}
};
abstract
void
apply();
}
}
|
通过策略枚举的方式,我们把Day的处理逻辑委托给了DayType,个中奥妙,读者可以细细体会.
枚举集合 EnumSet的使用 。
EnumSet提供了非常方便的方法来创建枚举集合,下面这段代码,感受一下 。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
public
class
Text {
public
enum
Style {
BOLD, ITALIC, UNDERLINE, STRIKETHROUGH
}
// Any Set could be passed in, but EnumSet is clearly best
public
void
applyStyles(Set<Style> styles) {
// Body goes here
for
(Style style : styles){
System.out.println(style);
}
}
// Sample use
public
static
void
main(String[] args) {
Text text =
new
Text();
text.applyStyles(EnumSet.of(Style.BOLD, Style.ITALIC));
}
}
|
这个例子里,我们使用了EnumSet.of方法,轻松创建了枚举集合.
枚举Map EnumMap的使用 。
假设对于香草(Herb),有一个枚举属性Type(一年生、多年生、两年生) 。
Herb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
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;
}
}
|
现在,假设我们有一个Herb数组,我们需要对这个Herb数组按照Type进行分类存放.
所以接下来,我们需要创建一个Map,value肯定是Herb的集合了,那么用什么作为key呢?
有的人会使用枚举类型的ordinal()方法,这个函数返回int类型,表示枚举遍历在枚举类里的位置,这样做,缺点很明显,由于你的key的类型是int,不能保证传入的int一定能和枚举类里的变量对应上.
所以,在key的选择上,毫无疑问,只能使用枚举类型,也即Herb.Type.
最后还有一个问题,要使用什么Map? Java为枚举类型专门提供了一种Map,叫EnumMap,相比较与其他Map,这种Map在处理枚举类型上更快,有兴趣的同学可以研究一下这个map的内部实现.
下面让我们看看怎么使用EnumMap:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
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);
}
|
总结 。
和int枚举相比,Enum枚举的在类型安全和使用便利上的优势是不言而喻的。 Enum为枚举提供了丰富的功能,如文章中提到的特定于常量的方法实现和策略枚举。 EnumSet和EnumMap是两个为枚举而设计的集合,在实际开发中,用到枚举集合时,请优先考虑这两个.
如有疑问请留言或者到本站社区交流讨论,感谢阅读,希望能帮助到大家,谢谢大家对本站的支持! 。
原文链接:http://blog.csdn.net/hzy38324/article/details/72566678 。
最后此篇关于Java枚举的使用方法详解的文章就讲到这里了,如果你想了解更多关于Java枚举的使用方法详解的内容请搜索CFSDN的文章或继续浏览相关文章,希望大家以后支持我的博客! 。
我正在编写一个具有以下签名的 Java 方法。 void Logger(Method method, Object[] args); 如果一个方法(例如 ABC() )调用此方法 Logger,它应该
我是 Java 新手。 我的问题是我的 Java 程序找不到我试图用作的图像文件一个 JButton。 (目前这段代码什么也没做,因为我只是得到了想要的外观第一的)。这是我的主课 代码: packag
好的,今天我在接受采访,我已经编写 Java 代码多年了。采访中说“Java 垃圾收集是一个棘手的问题,我有几个 friend 一直在努力弄清楚。你在这方面做得怎么样?”。她是想骗我吗?还是我的一生都
我的 friend 给了我一个谜语让我解开。它是这样的: There are 100 people. Each one of them, in his turn, does the following
如果我将使用 Java 5 代码的应用程序编译成字节码,生成的 .class 文件是否能够在 Java 1.4 下运行? 如果后者可以工作并且我正在尝试在我的 Java 1.4 应用程序中使用 Jav
有关于why Java doesn't support unsigned types的问题以及一些关于处理无符号类型的问题。我做了一些搜索,似乎 Scala 也不支持无符号数据类型。限制是Java和S
我只是想知道在一个 java 版本中生成的字节码是否可以在其他 java 版本上运行 最佳答案 通常,字节码无需修改即可在 较新 版本的 Java 上运行。它不会在旧版本上运行,除非您使用特殊参数 (
我有一个关于在命令提示符下执行 java 程序的基本问题。 在某些机器上我们需要指定 -cp 。 (类路径)同时执行java程序 (test为java文件名与.class文件存在于同一目录下) jav
我已经阅读 StackOverflow 有一段时间了,现在我才鼓起勇气提出问题。我今年 20 岁,目前在我的家乡(罗马尼亚克卢日-纳波卡)就读 IT 大学。足以介绍:D。 基本上,我有一家提供簿记应用
我有 public JSONObject parseXML(String xml) { JSONObject jsonObject = XML.toJSONObject(xml); r
我已经在 Java 中实现了带有动态类型的简单解释语言。不幸的是我遇到了以下问题。测试时如下代码: def main() { def ks = Map[[1, 2]].keySet()
一直提示输入 1 到 10 的数字 - 结果应将 st、rd、th 和 nd 添加到数字中。编写一个程序,提示用户输入 1 到 10 之间的任意整数,然后以序数形式显示该整数并附加后缀。 public
我有这个 DownloadFile.java 并按预期下载该文件: import java.io.*; import java.net.URL; public class DownloadFile {
我想在 GUI 上添加延迟。我放置了 2 个 for 循环,然后重新绘制了一个标签,但这 2 个 for 循环一个接一个地执行,并且标签被重新绘制到最后一个。 我能做什么? for(int i=0;
我正在对对象 Student 的列表项进行一些测试,但是我更喜欢在 java 类对象中创建硬编码列表,然后从那里提取数据,而不是连接到数据库并在结果集中选择记录。然而,自从我这样做以来已经很长时间了,
我知道对象创建分为三个部分: 声明 实例化 初始化 classA{} classB extends classA{} classA obj = new classB(1,1); 实例化 它必须使用
我有兴趣使用 GPRS 构建车辆跟踪系统。但是,我有一些问题要问以前做过此操作的人: GPRS 是最好的技术吗?人们意识到任何问题吗? 我计划使用 Java/Java EE - 有更好的技术吗? 如果
我可以通过递归方法反转数组,例如:数组={1,2,3,4,5} 数组结果={5,4,3,2,1}但我的结果是相同的数组,我不知道为什么,请帮助我。 public class Recursion { p
有这样的标准方式吗? 包括 Java源代码-测试代码- Ant 或 Maven联合单元持续集成(可能是巡航控制)ClearCase 版本控制工具部署到应用服务器 最后我希望有一个自动构建和集成环境。
我什至不知道这是否可能,我非常怀疑它是否可能,但如果可以,您能告诉我怎么做吗?我只是想知道如何从打印机打印一些文本。 有什么想法吗? 最佳答案 这里有更简单的事情。 import javax.swin
我是一名优秀的程序员,十分优秀!