浅谈在Java开发中的枚举的作用和用法
枚举(enum),是指一个经过排序的、被打包成一个单一实体的项列表。一个枚举的实例可以使用枚举项列表中任意单一项的值。枚举在各个语言当中都有着广泛的应用,通常用来表示诸如颜色、方式、类别、状态等等数目有限、形式离散、表达又极为明确的量。Java从JDK5开始,引入了对枚举的支持。
在枚举出现之前,如果想要表示一组特定的离散值,往往使用一些常量。例如:
package com.fhp.enumexample; public class Entity { public static final int VIDEO = 1;//视频
public static final int AUDIO = 2;//音频
public static final int TEXT = 3;//文字
public static final int IMAGE = 4;//图片 private int id;
private int type; public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public int getType() {
return type;
}
public void setType(int type) {
this.type = type;
} }
当然,常量也不仅仅局限于int型,诸如char和String等也是不在少数。然而,无论使用什么样的类型,这样做都有很多的坏处。这些常量通常都是连续、有无穷多个值的量,而类似这种表示类别的量则是离散的,并且通常情况下只有有限个值。用连续的量去表示离散量,会产生很多问题。例如,针对上述的Entity类,如果要对Entity对象的type属性进行赋值,一般会采用如下方法:
Entity e = new Entity();
e.setId(10);
e.setType(2);
这样做的缺点有:(1)代码可读性差、易用性低。由于setType()方法的参数是int型的,在阅读代码的时候往往会让读者感到一头雾水,根本不明白这个2到底是什么意思,代表的是什么类型。当然,要保证可读性,还有这样一个办法:
e.setType(Entity.AUDIO);
而这样的话,问题又来了。这样做,客户端必须对这些常量去建立理解,才能了解如何去使用这个东西。说白了,在调用的时候,如果用户不到Entity类中去看看,还真不知道这个参数应该怎么传、怎么调。像是setType(2)这种用法也是在所难免,因为它完全合法,不是每个人都能够建立起用常量名代替数值,从而增加程序可读性、降低耦合性的意识。
(2)类型不安全。在用户去调用的时候,必须保证类型完全一致,同时取值范围也要正确。像是setType(-1)这样的调用是合法的,但它并不合理,今后会为程序带来种种问题。也许你会说,加一个有效性验证嘛,但是,这样做的话,又会引出下面的第(3)个问题。
(3)耦合性高,扩展性差。假如,因为某些原因,需要修改Entity类中常量的值,那么,所有用到这些常量的代码也就都需要修改——当然,要仔细地修改,万一漏了一个,那可不是开玩笑的。同时,这样做也不利于扩展。例如,假如针对类别做了一个有效性验证,如果类别增加了或者有所变动,则有效性验证也需要做对应的修改,不利于后期维护。
枚举就是为了这样的问题而诞生的。它们给出了将一个任意项同另一个项相比较的能力,并且可以在一个已定义项列表中进行迭代。枚举(在Jave中简称为enum)是一个特定类型的类。所有枚举都是Java中的新类java.lang.Enum的隐式子类。此类不能手工进行子类定义。一个简单的枚举可以是这样:
package com.fhp.enumexample; public enum TypeEnum {
VIDEO, AUDIO, TEXT, IMAGE
}
上面的Entity类就可以改成这样:
package com.fhp.enumexample; public class Entity { private int id;
private TypeEnum type; public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
} public TypeEnum getType() {
return type;
}
public void setType(TypeEnum type) {
this.type = type;
}
}
在为Entity对象赋值的时候,就可以这样:
Entity e = new Entity();
e.setId(10);
e.setType(TypeEnum.AUDIO);
怎么看,都是好了很多。在调用setType()时,可选值只有四个,否则会出现编译错误,因此可以看出,枚举是类型安全的,不会出现取值范围错误的问题。同时,客户端不需要建立对枚举中常量值的了解,使用起来很方便,并且可以容易地对枚举进行修改,而无需修改客户端。如果常量从枚举中被删除了,那么客户端将会失败并且将会收到一个错误消息。枚举中的常量名称可以被打印,因此除了仅仅得到列表中项的序号外还可以获取更多信息。这也意味着常量可用作集合的名称,例如HashMap。
因为在Java中一个枚举就是一个类,它也可以有属性和方法,并且实现接口。只是所有的枚举都继承自java.lang.Enum类,因此enum不可以再继承其他的类。
下面给出在枚举中声明属性和方法的示例:
package com.fhp.enumexample; public enum TypeEnum {
VIDEO(1), AUDIO(2), TEXT(3), IMAGE(4); int value; TypeEnum(int value) {
this.value = value;
} public int getValue() {
return value;
}
}
在这个枚举中,每个枚举的值都有一个对应的int型字段,而且不同的枚举值也会有不同的int数值。同时,它和普通的类一样,可以声明构造器和各种各样的方法。如:
TypeEnum type = TypeEnum.TEXT;//type的value属性值为3。
System.out.println(type.getValue());//屏幕输出3。
如果要为每个枚举值指定属性,则在枚举中必须声明一个参数为属性对应类型的构造方法(不能是public)。否则编译器将给出The constructor TypeEnum(int, String) is undefined的错误。在此例中,属性为int型,因此构造方法应当为int型。除此之外,还可以为枚举指定多个属性,如:
package com.fhp.enumexample; public enum TypeEnum {
VIDEO(1, "视频"), AUDIO(2, "音频"), TEXT(3, "文本"), IMAGE(4, "图像"); int value;
String name; TypeEnum(int value, String name) {
this.value = value;
this.name = name;
} public int getValue() {
return value;
} public String getName() {
return name;
}
}
enum还内置了许多方法,常用的如下:
int compareTo(E o)
比较此枚举与指定对象的顺序。
Class<E> getDeclaringClass()
返回与此枚举常量的枚举类型相对应的 Class 对象。
String name()
返回此枚举常量的名称,在其枚举声明中对其进行声明。
int ordinal()
返回枚举常量的序数(它在枚举声明中的位置,其中初始常量序数为零)。
String toString()
返回枚举常量的名称,它包含在声明中。
static <T extends Enum<T>> T valueOf(Class<T> enumType, String name)
返回带指定名称的指定枚举类型的枚举常量。
static T[] values()
返回该枚举的所有值。
现在,假设要为该枚举实现一个根据整数值生成枚举值的方法,可以这样做:
package com.fhp.enumexample; public enum TypeEnum {
VIDEO(1, "视频"), AUDIO(2, "音频"), TEXT(3, "文本"), IMAGE(4, "图像"); int value;
String name; TypeEnum(int value, String name) {
this.value = value;
this.name = name;
} public int getValue() {
return value;
} public String getName() {
return name;
} public static TypeEnum getByValue(int value) {
for(TypeEnum typeEnum : TypeEnum.values()) {
if(typeEnum.value == value) {
return typeEnum;
}
}
throw new IllegalArgumentException("No element matches " + value);
}
}
getByValue(int)即为整数值转枚举值的方法。调用values()方法获取到该枚举下的所有值,然后遍历该枚举下面的每个值和给定的整数是否匹配,若匹配直接返回,若无匹配值则抛出IllegalArgumentException异常,表示参数不合法,兼有有效性验证的作用。
综上,我们可以看到,在JDK5中新引入的枚举完美地解决了之前通过常量来表示离散量所带来的问题,大大加强了程序的可读性、易用性和可维护性,并且在此基础之上又进行了扩展,使之可以像类一样去使用,更是为Java对离散量的表示上升了一个台阶。因此,如果在Java中需要表示诸如颜色、方式、类别、状态等等数目有限、形式离散、表达又极为明确的量,应当尽量舍弃常量表示的做法,而将枚举作为首要的选择。
浅谈在Java开发中的枚举的作用和用法的更多相关文章
- java开发中使用枚举表述数据字典
一.用枚举表述数据字典 1.代码: package com.inspire.jdk.caculate; /** * Created by yaming * 用枚举表述常量数据字段 */ public ...
- 【Unity游戏开发】浅谈Unity游戏开发中的单元测试
一.单元测试的定义与作用 单元测试定义:单元测试在传统软件开发中是非常重要的工具,它是指对软件中的最小可测试单元进行检查和验证,一般情况下就是对代码中的一个函数去进行验证,检查它的正确性.一个单元测试 ...
- 浅谈Android系统开发中LOG的使用
文章转载至CSDN社区罗升阳的安卓之旅,原文地址:http://blog.csdn.net/luoshengyang/article/details/6581828 在程序开发过程中,LOG是广泛使用 ...
- 浅谈Android系统开发中LOG的使用【转】
本文转载自:http://blog.csdn.net/luoshengyang/article/details/6581828 在程序开发过程中,LOG是广泛使用的用来记录程序执行过程的机制,它既可以 ...
- 浅谈iOS视频开发
浅谈iOS视频开发 这段时间对视频开发进行了一些了解,在这里和大家分享一下我自己觉得学习步骤和资料,希望对那些对视频感兴趣的朋友有些帮助. 一.iOS系统自带播放器 要了解iOS视频开发,首先我们从 ...
- Java开发中常见的危险信号(上)
本文来源于我在InfoQ中文站原创的文章,原文地址是:http://www.infoq.com/cn/news/2013/12/common-red-flags-in-java-1 Dustin Ma ...
- 浅谈线程池(中):独立线程池的作用及IO线程池
原文地址:http://blog.zhaojie.me/2009/07/thread-pool-2-dedicate-pool-and-io-pool.html 在上一篇文章中,我们简单讨论了线程池的 ...
- Java开发中常见的危险信号(中)
本文来源于我在InfoQ中文站原创的文章,原文地址是:http://www.infoq.com/cn/news/2013/12/common-red-flags-in-java-1 Dustin Ma ...
- Java 开发中如何正确踩坑
为什么说一个好的员工能顶 100 个普通员工 我们的做法是,要用最好的人.我一直都认为研发本身是很有创造性的,如果人不放松,或不够聪明,都很难做得好.你要找到最好的人,一个好的工程师不是顶10个,是顶 ...
随机推荐
- Android输入法框架系统(下)
程序焦点获取事件导致输入法显示 从上面可以知道程序获得焦点时,程序端会先间接的调用IMMS的startInput将焦点View绑定到输入法,然后会调用IMMS的windowGainFocus函数,这个 ...
- 离线使用Visual Studio的Javascript Prettier插件
用Prettier插件来格式化Javascript代码效果好的不得了,简直是强迫症的救命克星,可惜单位的电脑是不联网的,始终用不了,今天抽空研究了一下,找到办法了. 1.下载JavaScript Pr ...
- Swift3 中文手册.CHM版
根据官方翻译制作Swift3 中文手册.CHM版已完成. Swift3 中文手册.CHM版下载地址
- Maven项目中的配置
1 在配置好Maven项目后,新建一个Maven Project.如图 点击next,会进入如下界面: 选择webapp,不选择默认的quickstart,之后会进入以下界面 填好Group ID 和 ...
- Navicat Premium连接PostgreSQL
连接PostgreSQL时,报错 大致意思:你当前的IP没有连接权限,在文件pg_hba中缺少当前IP的配置 解决:找你的PostgreSQL安装路径,这是我的:C:\Program Files\Po ...
- 【转载】Python字符串操作之字符串分割与组合
1. str.split():字符串分割函数 通过指定分隔符对字符串进行切片,并返回分割后的字符串列表. 语法: str.split(s, num)[n] 参数说明: s:表示指定的分隔符,不写的话, ...
- poj1797 最短路
虽然不是求最短路,但是仍然是最短路题目,题意是要求1到N点的一条路径,由于每一段路都是双向的并且有承受能力,求一条路最小承受能力最大,其实就是之前POJ2253的翻版,一个求最大值最小,一个求最小值最 ...
- <frameset>框架集中不同<frame>之间的调用【js代码中】
top:永远指分割窗口最高层次的浏览器窗口;parent:包含当前分割窗口的父窗口,本文将围绕js中top.parent.frame进行讲述及他们的应用案例 引用方法top: 该变量永远指分割窗口最高 ...
- LG1397 [NOI2013]矩阵游戏
题意 婷婷是个喜欢矩阵的小朋友,有一天她想用电脑生成一个巨大的n行m列的矩阵(你不用担心她如何存储).她生成的这个矩阵满足一个神奇的性质:若用F[i][j]来表示矩阵中第i行第j列的元素,则F[i][ ...
- JNI学习笔记_Java调用C —— Android中使用的方法
一.笔记 1.JNI(Java Native Interface),就是如何使用java去访问C/C++编写的那些库.若想深入了解JNI可以看官方文档jni.pdf.优秀博文:Android JNI知 ...