2019独角兽企业重金招聘Python工程师标准>>>

在枚举出现之前,如果想要表示一组特定的离散值,往往使用一些常量。例如: [java] view plain copy

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属性进行赋值,一般会采用如下方法:

[java] view plain copy

Entity e = new Entity();
e.setId(10);
e.setType(2);

这样做的缺点有:(1)代码可读性差、易用性低。由于setType()方法的参数是int型的,在阅读代码的时候往往会让读者感到一头雾水,根本不明白这个2到底是什么意思,代表的是什么类型。当然,要保证可读性,还有这样一个办法:

[java] view plain copy

e.setType(Entity.AUDIO);

而这样的话,问题又来了。这样做,客户端必须对这些常量去建立理解,才能了解如何去使用这个东西。说白了,在调用的时候,如果用户不到Entity类中去看看,还真不知道这个参数应该怎么传、怎么调。像是setType(2)这种用法也是在所难免,因为它完全合法,不是每个人都能够建立起用常量名代替数值,从而增加程序可读性、降低耦合性的意识。

(2)类型不安全。在用户去调用的时候,必须保证类型完全一致,同时取值范围也要正确。像是setType(-1)这样的调用是合法的,但它并不合理,今后会为程序带来种种问题。也许你会说,加一个有效性验证嘛,但是,这样做的话,又会引出下面的第(3)个问题。

(3)耦合性高,扩展性差。假如,因为某些原因,需要修改Entity类中常量的值,那么,所有用到这些常量的代码也就都需要修改——当然,要仔细地修改,万一漏了一个,那可不是开玩笑的。同时,这样做也不利于扩展。例如,假如针对类别做了一个有效性验证,如果类别增加了或者有所变动,则有效性验证也需要做对应的修改,不利于后期维护。

枚举就是为了这样的问题而诞生的。它们给出了将一个任意项同另一个项相比较的能力,并且可以在一个已定义项列表中进行迭代。枚举(在Jave中简称为enum)是一个特定类型的类。所有枚举都是Java中的新类java.lang.Enum的隐式子类。此类不能手工进行子类定义。一个简单的枚举可以是这样:

[java] view plain copy

package com.fhp.enumexample;  public enum TypeEnum {  VIDEO, AUDIO, TEXT, IMAGE
}

上面的Entity类就可以改成这样:

[java] view plain copy

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对象赋值的时候,就可以这样:

[java] view plain copy

Entity e = new Entity();
e.setId(10);
e.setType(TypeEnum.AUDIO);

怎么看,都是好了很多。在调用setType()时,可选值只有四个,否则会出现编译错误,因此可以看出,枚举是类型安全的,不会出现取值范围错误的问题。同时,客户端不需要建立对枚举中常量值的了解,使用起来很方便,并且可以容易地对枚举进行修改,而无需修改客户端。如果常量从枚举中被删除了,那么客户端将会失败并且将会收到一个错误消息。枚举中的常量名称可以被打印,因此除了仅仅得到列表中项的序号外还可以获取更多信息。这也意味着常量可用作集合的名称,例如HashMap。

因为在Java中一个枚举就是一个类,它也可以有属性和方法,并且实现接口。只是所有的枚举都继承自java.lang.Enum类,因此enum不可以再继承其他的类。

下面给出在枚举中声明属性和方法的示例:

[java] view plain copy

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数值。同时,它和普通的类一样,可以声明构造器和各种各样的方法。如:

[java] view plain copy

TypeEnum type = TypeEnum.TEXT;//type的value属性值为3。
System.out.println(type.getValue());//屏幕输出3。

如果要为每个枚举值指定属性,则在枚举中必须声明一个参数为属性对应类型的构造方法(不能是public)。否则编译器将给出The constructor TypeEnum(int, String) is undefined的错误。在此例中,属性为int型,因此构造方法应当为int型。除此之外,还可以为枚举指定多个属性,如:

[java] view plain copy

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()

返回该枚举的所有值。

现在,假设要为该枚举实现一个根据整数值生成枚举值的方法,可以这样做:

[java] view plain copy

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 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 枚举7常见种用法**

用法一:常量

在JDK1.5 之前,我们定义常量都是: publicstaticfianl.... 。现在好了,有了枚举,可以把相关的常量分组到一个枚举类型里,而且枚举提供了比常量更多的方法。

Java代码

public enum Color {  RED, GREEN, BLANK, YELLOW
}

用法二:switch

JDK1.6之前的switch语句只支持int,char,enum类型,使用枚举,能让我们的代码可读性更强。

Java代码

enum Signal {  GREEN, YELLOW, RED
}
public class TrafficLight {  Signal color = Signal.RED;  public void change() {  switch (color) {  case RED:  color = Signal.GREEN;  break;  case YELLOW:  color = Signal.RED;  break;  case GREEN:  color = Signal.YELLOW;  break;  }  }
}

用法三:向枚举中添加新方法

如果打算自定义自己的方法,那么必须在enum实例序列的最后添加一个分号。而且 Java 要求必须先定义 enum 实例。

Java代码

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;  }  // 普通方法  public static String getName(int index) {  for (Color c : Color.values()) {  if (c.getIndex() == index) {  return c.name;  }  }  return null;  }  // get set 方法  public String getName() {  return name;  }  public void setName(String name) {  this.name = name;  }  public int getIndex() {  return index;  }  public void setIndex(int index) {  this.index = index;  }
}

用法四:覆盖枚举的方法

下面给出一个toString()方法覆盖的例子。

Java代码

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](https://my.oschina.net/u/1162528)  public String toString() {  return this.index+"_"+this.name;  }
}

用法五:实现接口

所有的枚举都继承自java.lang.Enum类。由于Java 不支持多继承,所以枚举对象不能再继承其他类。

Java代码

public interface Behaviour {  void print();  String getInfo();
}
public enum Color implements Behaviour{  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](https://my.oschina.net/u/1162528)  public String getInfo() {  return this.name;  }  //接口方法  [@Override](https://my.oschina.net/u/1162528)  public void print() {  System.out.println(this.index+":"+this.name);  }
}

用法六:使用接口组织枚举

Java代码

public interface Food {  enum Coffee implements Food{  BLACK_COFFEE,DECAF_COFFEE,LATTE,CAPPUCCINO  }  enum Dessert implements Food{  FRUIT, CAKE, GELATO  }
}

用法七:关于枚举集合的使用

java.util.EnumSet和java.util.EnumMap是两个枚举集合。EnumSet保证集合中的元素不重复;EnumMap中的 key是enum类型,而value则可以是任意类型。关于这个两个集合的使用就不在这里赘述,可以参考JDK文档。

关于枚举的实现细节和原理请参考:

参考资料:《ThinkingInJava》第四版

转载于:https://my.oschina.net/sunhacker/blog/1587260

浅谈在Java开发中的枚举的作用和用法相关推荐

  1. 嵌入式开发-浅谈嵌入式MCU开发中的三个常见误区

    浅谈嵌入式MCU开发中的三个常见误区 原创 2017-09-30 胡恩伟 汽车电子expert成长之路 目录 (1)嵌入式MCU与MPU的区分 (2)误区一:MCU的程序都是存储在片上Flash上,然 ...

  2. 【干货】Redis在Java开发中的基本使用和巧妙用法

    Redis是一款高性能的内存数据结构存储系统,能够支持多种数据结构类型,如字符串.哈希.列表.集合.有序集合等,也能够支持高级功能,如事务.发布/订阅.Lua脚本等,具有高可用性.高并发性和可扩展性的 ...

  3. 浅谈 Quartz2D 在开发中的用处 - 图形的状态

    转载自:http://www.tuicool.com/articles/R3MVJ3Q 相比之前的画图形应该都掌握了.在开发中图形的状态还是存在的,比如电脑桌面壁纸的平铺.拉伸.居中等.下面将逐个介绍 ...

  4. 浅谈Android系统开发中LOG的使用【转】

    本文转载自:http://blog.csdn.net/luoshengyang/article/details/6581828 在程序开发过程中,LOG是广泛使用的用来记录程序执行过程的机制,它既可以 ...

  5. 浅谈Android系统开发中LOG的使用

    文章转载至CSDN社区罗升阳的安卓之旅,原文地址:http://blog.csdn.net/luoshengyang/article/details/6581828 在程序开发过程中,LOG是广泛使用 ...

  6. 浅谈在软件开发中的开发与测试 - 下

    介绍了一下测试的必要性,再回过头来继续说开发与测试的"矛盾",其实这个矛盾从本质上来说是由于绩效管理时过分强调了开发人员造成的Bug,而这个"过分强调"又必须是 ...

  7. Android Java开发中一些唬人的常用关键字用法,持续更新中。。。

    一,return语句 最常用的是返回方法指定类型的值(这个值总是确定的), 另一种用的相对较少的用法是结束方法的执行(仅仅一个return语句). 二.布局中容易忽视的属性方法 ①setClipChi ...

  8. Java开发中常见的危险信号

    Dustin Marx是一位专业软件开发者,从业已经有17年的时间,他拥有电子工程学士学位,还是一位MBA.Dustin维护着一个博客,专门介绍软件开发的各个主题.近日,他撰文谈到了Java开发中常见 ...

  9. 浅谈计算机逻辑学,浅谈逻辑在计算机科学中的应用

    龙源期刊网 http://doc.docsou.com 浅谈逻辑在计算机科学中的应用 作者:耿云磊 来源:<中国科技博览>2017年第15期 [摘要]逻辑是计算机科学的灵魂.本文通过对逻辑 ...

最新文章

  1. 技术图文:如何爬取一个地区的气象数据(下)?
  2. excel html modify,在Excel 2010中修改Series对象上的Z-index(Modify Z-index on Series object in Excel 2010)...
  3. 基于jquery的ajax聊天室系统,基于jQuery的Ajax聊天室应用毕业设计(含外文翻译)...
  4. 西交大计算机考博学术英语,2018年西安交通大学考博英语真题
  5. pandas从dataframe中选择部分行、列
  6. php 压缩动态gif,php 压缩图片处理png、gif背景变黑问题
  7. 微星笔记本win键失灵了怎么解决
  8. educoder 1-1Python 计算思维训练——公式编程
  9. java通过qq邮箱发送_java通过qq邮箱发送邮件
  10. 用Python制作一个文件加密器(支持中文)
  11. 资深程序员雷总对代码的执念
  12. fsck|xfs_repair 磁盘修复
  13. 5本财富自由好书的精华
  14. java和scala代码可以混合编写吗_IDEA实现Java与Scala代码混合开发
  15. android 7.0 手机拍照裁剪问题
  16. Flash Socket 的基本通讯协议流程例子
  17. P2P DHT sp
  18. [总结]读取应用程序/类库配置文件(比如***.dll.config)的方法小结
  19. Duplicated tag: ‘mirrors‘ (position: START_TAG seen ...erred\r\n
  20. 2021-10-12 集合

热门文章

  1. 为什么socket接收大数据的时候接收不完全,出现丢包?
  2. 在对linux系统分区进行格式化时需要对磁盘簇(或i节点密度)的大小进行选择,请说明选择的原则。
  3. 三种工厂模式的分析以及C++实现
  4. springboot自动配置流程
  5. 解决浏览器保存密码自动填充问题
  6. Android adb你真的会用吗?
  7. 【Oracle】Oracle常用EVENT之三
  8. HDU-1299 Diophantus of Alexandria 素因子分解
  9. WINDOWS与LINUX下的DNS轮询配置
  10. Raspberry Pi 4B 颜色检测