枚举(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高级特性(4)--枚举的更多相关文章

  1. Java高级特性之枚举学习总结

    在Java SE5之前,我们要使用枚举类型时,通常会使用static final 定义一组int常量来标识,代码如下 public static final int MAN = 0; public s ...

  2. Java高级特性之枚举

    在Java SE5之前,我们要使用枚举类型时,通常会使用static final 定义一组int常量来标识,代码如下 public static final int MAN = 0; public s ...

  3. java高级特性增强

    第4天 java高级特性增强 今天内容安排: 1.掌握多线程 2.掌握并发包下的队列 3.了解JMS 4.掌握JVM技术 5.掌握反射和动态代理 java多线程增强 .1. java多线程基本知识 . ...

  4. paip。java 高级特性 类默认方法,匿名方法+多方法连续调用, 常量类型

    paip.java 高级特性 类默认方法,匿名方法+多方法连续调用, 常量类型 作者Attilax 艾龙,  EMAIL:1466519819@qq.com 来源:attilax的专栏 地址:http ...

  5. Java高级特性-String、StringBuffer和StringBuilder

    Java高级特性-String.StringBuffer和StringBuilder String Java语言中的字符串值都属于String类,虽然有其他方法表示字符串(如字符串数组),但Java一 ...

  6. Java高级特性——反射机制(第二篇)

    在Java高级特性——反射机制(第一篇)中,写了很多反射的实例,可能对于Class的了解还是有点迷糊,那么我们试着从内存角度去分析一下. Java内存 从上图可以看出,Java将内存分为堆.栈.方法区 ...

  7. Java高级特性1_流库_初体验

    Java高级特性流库_初体验 面对结果编程 在编程里, 有两种编程方式, 一种是面对过程编程, 一种是面对结果编程. 两者区别如下 面向过程编程 面向过程编程需要编程程序让程序依次执行得到自己想要的结 ...

  8. 云端卫士实战录 | Java高级特性之多线程

    <实战录>导语 一转眼作为一名Java开发者已经四年多时间了,说长不长说短不短,对于java的感情还是比较深的,主要嘛毕竟它给了我饭吃.哈哈,开个玩笑.今天我想借此机会来和大家聊聊Java ...

  9. Java高级特性之泛型

    首先我们先提出两个问题: 什么是泛型? 为什么要使用泛型?我们先来看看第一个问题什么是泛型.如果你对Java三大特性中的多态性理解的比较透彻的话,泛型就比较好理解了.多态性表示一个对象具备多种状态.比 ...

  10. JAVA 高级特性枚举和泛型

    枚举: 语法:  public enum 枚举名 { 枚举值表(罗列所有值) }  例如:  public enum EnumTest{MON,TUE,WED.THU,FRI,SAT,SUN} 枚举操 ...

随机推荐

  1. oracle查看被锁的表和被锁的进程,杀掉进程

    -- 1. 查看被锁的表 SELECT p.spid, a.serial#, c.object_name, b.session_id, b.oracle_username,b.os_user_name ...

  2. Python 连接 Oracle数据库

    1.环境设置 [root@oracle ~]# cat /etc/redhat-release CentOS release 6.9 (Final) [root@oracle ~]# python - ...

  3. 超简单Centos+Docker+Halo搭建java向博客

    首先,我就当你们了解docker基本知识了. 直接开始,全新的系统. 1. 安装Docker 移除旧的版本:  $ sudo yum remove docker \                  ...

  4. 【spring-boot】spring-boot整合ehcache实现缓存机制

    EhCache 是一个纯Java的进程内缓存框架,具有快速.精干等特点,是Hibernate中默认的CacheProvider. ehcache提供了多种缓存策略,主要分为内存和磁盘两级,所以无需担心 ...

  5. springboot使用tomcat apr模式

    因需项目对并发要求比较高.提高Tomcat效率.使用tomcat apr模式.今天在这记录下使用过程.apr全称为apache portable runtime.这里套用下wiki对apr的解释. T ...

  6. 20165324 Java实验三 敏捷开发与XP实验

    20165324 Java实验三 敏捷开发与XP实验 一.实验报告封面 课程:Java程序设计 班级:1653班 姓名:何春江 学号:20165324 指导教师:娄嘉鹏 实验日期:2018年4月16日 ...

  7. Java基础知识陷阱(七)

    本文发表于本人博客. 上次说了下HashSet和HashMap之间的关系,其中HashMap这个内部有这么一句: static final float DEFAULT_LOAD_FACTOR = 0. ...

  8. 一步一步学EF系列四【升级篇 实体与数据库的映射】

    之前的三张为基础篇,如果不考虑架构问题,做一般的小程序,以足够用了.基本的增删改查也都有了.但是作为学习显然是不够的.通过之前三章的学习,有没有发现这样写有什么问题,有没有觉得繁琐的?可能有人会说,之 ...

  9. 本地idea开发mapreduce程序提交到远程hadoop集群执行

    https://www.codetd.com/article/664330 https://blog.csdn.net/dream_an/article/details/84342770 通过idea ...

  10. Glide Picasso和Fresco的对比

    比较Picasso.Glide 和 Fresco 三种图片加载库 比较 Picasso 与 Glide 总体来说二者极为相似,有着近乎相同的 API 的使用风格,但 Glide 在缓存策略和加载 gi ...