Java枚举

枚举类概念的理解与定义

  • 一个类的对象是有限个,确定的,我们称此为枚举类。
  • 当需要定义和维护一组常量时,强烈建议使用枚举类。
  • 如果一个枚举类中只有一个对象,则可以作为单例模式的实现方式。
通俗的说:一个类被设计为包含固定实例数量的特殊类,我们给他的定义是枚举类。

注意:
1.枚举类不能被 new 出来,枚举类因为默认的类修饰符为 final 所以也不能被派生(继承),同理枚举类也不能为当作实现。
2.枚举类自身可以实现接口,既可以进行统一实现重写接口抽象方法,也可以按照枚举类型单个实现重写。

枚举类的定义

关于枚举类的定义,这块主要想和大家分享两种方式

  1. jdk 5.0之前,自定义枚举类方式
  2. jdk 5.0之后,Enum关键字方式定义

实践

一、准备工作

我们新建一个 Java Project ,并创建一个包,以及一个测试类

二、自定义枚举的三种方式(jdk 5.0 之前)

1. 定义一个抽象类,在抽象类中定义常量进行维护,我们接下来以 Java 类库中的 Calendar 类示例来进行说明

新建一个类 EnumDemo01.java 代码如下:

package org.taoguoguo;
import java.util.Calendar; /**
* @author taoGG
* @description jdk 5.0 之前 抽象类枚举方案Demo
* @create 2020-09-13 14:20
*/
public class EnumDemo01 {
public static void main(String[] args) {
Calendar calendar = Calendar.getInstance();
System.out.println(calendar.get(1));
}
}

Console 结果输出:

2020
Process finished with exit code 0

如果熟悉 Calendar API 的小伙伴 应该马上能反应过来,这个是获取当前的年份,类似的值还有

3 - 一年中的第几个星期
4 - 一年中的第几个月
5 - 当前的日期
......

但是这么多值,我们怎么能记得住呢?万一我输入错误,随便取了一个范围怎么办?

没错,这是 jdk 5.0之前的痛点,为了解决实例数量固定,便于维护这些问题,在jdk 5.0之后更新Enum枚举类解决了这个问题。那在jdk 5.0之前官方是怎么做的呢?难道需要我们一个个去记住 Calendar 的数字?

实际上官方本身,采用的就是我们现在说的第一种方式,在抽象类中定义常量进行维护

现在我们将代码做些修改:

package org.taoguoguo;
import java.util.Calendar; /**
* @author taoGG
* @description jdk 5.0 之前 抽象类枚举方案Demo
* @create 2020-09-13 14:20
*/
public class EnumDemo01 {
public static void main(String[] args) {
Calendar calendar = Calendar.getInstance();
System.out.println(calendar.get(Calendar.YEAR));
}
}

我们运行进行输出:

2020
Process finished with exit code 0

结果与之前一致,这时我们就清楚,在开发过程中作为开发者我们肯定愿意使用 Calendar.YEAR 这种写法,一来方便记忆,二来可读性高。那么官方的做法时怎样的呢?我们点进去源码看一下

  1. 首先 Calendar 本身是一个抽象类,实现了序列化、克隆、以及比较排序接口,这边和我们枚举没有太大关系,我们继续往下看

  2. 在抽象类中,定义了很多个静态常量进行维护,而当我们需要使用时,直接调用,这样就比我们写一个个的具体值要方便和易用了。

2. 定义一个接口,在接口中定义常量维护枚举值

我们新建一个interface CustomerInf.java

package org.taoguoguo;

/**
* @author taoGG
* @description 接口常量维护枚举值
* @create 2020-09-13 15:47
*/
public interface CustomerInf {
int RED = 1;
int GREEN = 2;
int BLUE = 3;
}

EnumTest 进行测试

package org.taoguoguo;

/**
* @author taoGG
* @description Java枚举测试类
* @create 2020-09-13 14:54
*
*/
public class EnumTest {
public static void main(String[] args) {
System.out.println(CustomerInf.RED);
}
}

测试结果:

1
Process finished with exit code 0

这种做法我们达到了和在抽象类中维护常量相同的目的。上面这两种做法都非常的简单易用,但也有弊端。比如我们只知道一个状态值,当我们要获取状态的属性或者相关的内容时,我们该怎么做呢?

下面我们使用第三种方式,自定义枚举类,这种基本上达到和 Enum 关键字相同的作用,但有一点不足就是会较为复杂

3.自定义枚举类,通过为类私有化构造器和固定实例对象进行枚举维护

新建一个class SeasonEnum.java,代码如下:

package org.taoguoguo;

/**
* @author taoGG
* @description
* @create 2020-09-13 15:58
*/
public class SeasonEnum {
//1.声明枚举对象的属性
private final String seasonName;
private final int code; //2.私有化类的构造器
private SeasonEnum(String seasonName,int code){
this.seasonName = seasonName;
this.code = code;
} //3.提供当前枚举类的多个对象 public static final
public static final SeasonEnum SPRING = new SeasonEnum("春天",100);
public static final SeasonEnum SUMMER = new SeasonEnum("夏天",200);
public static final SeasonEnum AUTUMN = new SeasonEnum("秋天",300);
public static final SeasonEnum WINTER = new SeasonEnum("冬天",400); //4.为类提供获取属性的方法
public String getSeasonName() {
return seasonName;
}
public int getCode() {
return code;
}
//5.重写toString方法
@Override
public String toString() {
return "SeasonEnum{" +
"seasonName='" + seasonName + '\'' +
", code=" + code +
'}';
}
}

新建一个class SeasonEnumTest 进行测试,当我们通过自定义枚举类引用实例对象时,如下图可以看到,我们已经可以获取到我们的枚举对象了。



获取到枚举对象,我们当然也可以获取到对应的属性及方法,这种可用性就提高了很多,我们在开发程序进行判断,可以根据各种枚举值的指定属性来进行,提高了代码的可维护性。



SeasonEnumTest 测试代码

package org.taoguoguo;

/**
* @author taoGG
* @description
* @create 2020-09-13 16:04
*/
public class SeasonEnumTest {
public static void main(String[] args) {
SeasonEnum spring = SeasonEnum.SPRING;
System.out.println("自定义枚举类对象:" + spring);
System.out.println("自定义枚举类属性:" + spring.getSeasonName());
System.out.println("自定义枚举类属性:" + spring.getCode());
}
}

根据我们上面的自定义枚举类方式,我们基本已经实现了枚举的功能了,但是就像上面说到的,如果开发中枚举类型较多,开发多个这样的自定义枚举类会非常的耗时,所以 jdk 5.0 之后,推出了 Enum 关键字定义枚举类

三、Enum 关键字定义枚举类(jdk 5.0之后)

enum 全称为 enumeration,是jdk 5.0 中引入的新特性,在Java 中被 enum 关键字修饰的类型就是枚举类型

我们通过代码来示例来讲解和理解 enum 的用法,还是用我们刚刚自定以枚举类的例子,看看使用enum如何来写

新建一个Java class ,Kind 类型选择 enum 如图:



枚举类创建注意:

  • 枚举实例必须在 enum关键字声明的类中显式的指定(首行开始的以第一个分号结束)
  • 枚举不允许使用new,clone,反射,序列化手动创建枚举实例
package org.taoguoguo;

/**
* @author taoGG
* @description
* @create 2020-09-13 16:23
*/
public enum Season {
SPRING("春天",100),
SUMMER("夏天",200),
AUTUMN("秋天",300),
WINTER("冬天",400); private final String seasonName;
private final int code; Season(String seasonName, int code){
this.seasonName = seasonName;
this.code = code;
} public String getSeasonName() {
return seasonName;
}
public int getCode() {
return code;
}
}

使用 SeasonTest 测试类进行测试:

package org.taoguoguo;

/**
* @author taoGG
* @description
* @create 2020-09-13 16:27
*/
public class SeasonTest {
public static void main(String[] args) {
Season spring = Season.SPRING;
System.out.println(spring);
}
}

输出结果:

SPRING
Process finished with exit code 0

注意,在enmu 枚举类中如果没有重写 toString方法,会默认使用Enum类本身提供的 toString 方法,返回枚举类名称,因为定义的枚举类默认隐式继承于java.lang.Enum

1.枚举类主要方法介绍

  • values()  :该方法可以返回当前枚举类型的对象数组,可以很方便的遍历所有枚举值。一般我们可以根据枚举类的相关属性通过此方法遍历获取对应的枚举对象及枚举值
  • valueOf(String str) : 根据枚举类名称获取枚举类对象
  • toString(): 默认使用 java.lang.Enum的 toString方法,返回当前对象常量的名称,枚举类推荐重写返回自定义友好描述
  • name(): 返回当前枚举对象名称,和toString作用上类似,当时toString支持重写,name方法是不能重写的,在本质上 toString 也是调用的 name方法,枚举定义 name 方法就是为了返回枚举对象名称,而 toString 应该根据需要进行重写
  • ordinal(): 返回当前枚举对象的序号, 实现了 Comparable 接口,表明它是支持排序的 可以通过 Collections.sort 进行自动排序比较此枚举与指定对象的顺序
  • compareTo(): 基于ordinal进行序号大小比较

方式演示代码,小伙伴们可以自行运行输出一下,看看各个方法的作用,熟悉一下相关的方法api

package org.taoguoguo;

/**
* @author taoGG
* @description
* @create 2020-09-13 16:27
*/
public class SeasonTest {
public static void main(String[] args) {
System.out.println("========values()方法=======");
for (Season season : Season.values()) {
System.out.println(season);
}
System.out.println("==========================="); System.out.println("========valueOf方法========");
Season spring = Season.valueOf("SPRING");
System.out.println(spring);
System.out.println("==========================="); System.out.println("========toString方法========");
System.out.println(spring.toString());
System.out.println("==========================="); System.out.println("========name方法========");
System.out.println(spring.name());
System.out.println("==========================="); System.out.println("========ordinal方法========");
System.out.println(spring.ordinal());
System.out.println("==========================="); System.out.println("========compareTo方法========");
System.out.println(spring.compareTo(Season.WINTER));
System.out.println("===========================");
}
}

2.枚举类对接口的实现方式

准备工作

新建一个EnumInf 接口,定义一个抽象方法

package org.taoguoguo;

/**
* @author taoGG
* @description
* @create 2020-09-13 17:25
*/
public interface EnumInf {
void show();
}
1.实现接口,在enum中统一实现抽象方法

新建一个EnumInf 接口,定义抽象方法 show()

package org.taoguoguo;

/**
* @author taoGG
* @description
* @create 2020-09-13 17:25
*/
public interface EnumInf {
void show();
}

新建一个OrderStatus 枚举类 实现 EnumInf 接口

package org.taoguoguo;

/**
* @author taoGG
* @description
* @create 2020-09-13 17:27
*/
public enum OrderStatus implements EnumInf{ SUCCESS(200,"交易成功"),
Fail(500,"交易失败"); private final int code;
private final String desc; OrderStatus(int code, String desc){
this.code = code;
this.desc = desc;
} public int getCode() {
return code;
}
public String getDesc() {
return desc;
} /**
* 第一种方式,枚举统一重写接口抽象方法
*/
@Override
public void show() {
System.out.println("订单枚举对象");
}
}

进行测试

package org.taoguoguo;

/**
* @author taoGG
* @description
* @create 2020-09-13 17:32
*/
public class OrderStatusTest {
public static void main(String[] args) {
OrderStatus success = OrderStatus.SUCCESS;
success.show();
}
}

输出结果

订单枚举对象

Process finished with exit code 0

跟我们常用类实现没有什么区别,枚举也是可以统一实现的,那如果想针对不同的枚举对象进行不同状态的实现怎么办呢?比如我们的OA系统、或者电商系统中,根据不同状态 我们需要回写对应的数据,下面我们就来看看如何实现。

2.枚举对象分别实现接口中的抽象方法

案例跟接口统一实现一致,我们这边修改一下OrderStatus 枚举类,代码如下

package org.taoguoguo;

/**
* @author taoGG
* @description
* @create 2020-09-13 17:27
*/
public enum OrderStatus implements EnumInf{ SUCCESS(200,"交易成功") {
@Override
public void show() {
System.out.println("回写交易成功状态");
}
},
Fail(500,"交易失败") {
@Override
public void show() {
System.out.println("回写交易失败状态");
}
}; private final int code;
private final String desc; OrderStatus(int code, String desc){
this.code = code;
this.desc = desc;
} public int getCode() {
return code;
}
public String getDesc() {
return desc;
} }

我们再修改下测试类代码:

package org.taoguoguo;

/**
* @author taoGG
* @description
* @create 2020-09-13 17:32
*/
public class OrderStatusTest {
public static void main(String[] args) {
OrderStatus success = OrderStatus.SUCCESS;
success.show();
OrderStatus fail = OrderStatus.Fail;
fail.show();
}
}

输出结果

回写交易成功状态
回写交易失败状态 Process finished with exit code 0

通过这种方式就可以轻而易举地定义每个枚举实例不同的行为方式,也达到了我们预期的效果,其实在开发过程中根据枚举的设计和设计模式的铺垫可以极大的简化我们的业务代码。

3.Enum枚举类的工具类及应用场景

1.EnumSet 和 EnumMap

Java 中提供了两个方便操作enum的工具类——EnumSet 和 EnumMap。

EnumSet 是枚举类型的高性能 Set 实现。它要求放入它的枚举常量必须属于同一枚举类型。

// EnumSet的使用
System.out.println("EnumSet展示");
EnumSet<OrderStatus> errSet = EnumSet.allOf(OrderStatus.class);
for (OrderStatus e : errSet) {
System.out.println(e.name() + " : " + e.ordinal());
}

EnumMap 是专门为枚举类型量身定做的 Map 实现。虽然使用其它的 Map 实现(如HashMap)也能完成枚举类型实例到值得映射,但是使用 EnumMap 会更加高效:它只能接收同一枚举类型的实例作为键值,并且由于枚举类型实例的数量相对固定并且有限,所以 EnumMap 使用数组来存放与枚举类型对应的值。(计算机处理连续的资源使用局部内存效率更高)这使得 EnumMap 的效率非常高。

// EnumMap的使用
System.out.println("EnumMap展示");
EnumMap<StateMachine.Signal, String> errMap = new EnumMap(StateMachine.Signal.class);
errMap.put(StateMachine.Signal.RED, "红灯");
errMap.put(StateMachine.Signal.YELLOW, "黄灯");
errMap.put(StateMachine.Signal.GREEN, "绿灯");
for (Iterator<Map.Entry<StateMachine.Signal, String>> iter =errMap.entrySet().iterator(); iter.hasNext();) {
Map.Entry<StateMachine.Signal, String> entry = iter.next();
System.out.println(entry.getKey().name() + " : " + entry.getValue());
}
2.枚举类与 Switch 的配合使用

关于枚举与switch是个比较简单的话题,使用switch进行条件判断时,条件参数一般只能是整型,字符型。而枚举型确实也被switch所支持,在java 1.7后switch也对字符串进行了支持。

实践

新建一个 BizEnum 的java class,代码如下

package org.taoguoguo;

/**
* @author taoGG
* @description 企业类型枚举
* @create 2020-09-13 21:24
*/
public enum BizEnum { COUNTRIES(101,"国有企业"), PRIVETE(102,"私营企业"), SOHO(103,"个体单位"); private final int code;
private final String desc; BizEnum(int code, String desc){
this.code = code;
this.desc = desc;
} public int getCode() {
return code;
}
public String getDesc() {
return desc;
} //根据编码获取当前枚举对象的方法
public static BizEnum getBizTypeByCode(int code){
for (BizEnum bizEnum : BizEnum.values()) {
if(code == bizEnum.getCode()){
return bizEnum;
}
}
return null;
}
}

结合Switch进行测试

package org.taoguoguo;

/**
* @author taoGG
* @description
* @create 2020-09-13 21:31
*/
public class BizTest {
public static void main(String[] args) {
BizEnum bizType = BizEnum.getBizTypeByCode(101);
switch (bizType){
case COUNTRIES:
System.out.println("国有企业");
break;
case PRIVETE:
System.out.println("私营企业");
break;
case SOHO:
System.out.println("个体单位");
break;
default:
System.out.println("创业中");
}
}
}

输出结果:

国有企业

Process finished with exit code 0

总结

  1. jdk 5.0之前我们可以自定义枚举类,jdk 5.0之后使用enum关键字定义枚举类,枚举类默认继承自java.lang.Enum,使用枚举类将常量组织起来,便于统一管理。例如错误码状态机等场景中,较为合适使用枚举类。
  2. 枚举类常用方法介绍及枚举类实现抽象类、接口等抽象方法的两种方式。
  3. 枚举常用的工具类及与switch使用的场景。

Java枚举解读的更多相关文章

  1. Java枚举的用法和原理深入

    转载请注明原文地址:https://www.cnblogs.com/ygj0930/p/10843644.html 一:枚举的用法 1.定义和组织常量 在JDK1.5之前,我们定义常量都是:publi ...

  2. Java 枚举用法详解

    概念 enum 的全称为 enumeration, 是 JDK 1.5 中引入的新特性. 在Java中,被 enum 关键字修饰的类型就是枚举类型.形式如下: enum Color { RED, GR ...

  3. java 枚举类型分析

    最近做android开发,需要用到枚举值,这样可以连续赋值,我按之前c++那样书写,如下所示: public enum ColorSelect { RED_BAGE = 0, GREEN_BAGE, ...

  4. 【转】java枚举类型enum的使用

    原文网址:http://blog.csdn.net/wgw335363240/article/details/6359614 java 枚举类型enum 的使用 最近跟同事讨论问题的时候,突然同事提到 ...

  5. 【转】Java 枚举7常见种用法

    原文网址:http://softbeta.iteye.com/blog/1185573 Java 枚举7常见种用法 博客分类: java java枚举enmu  原创地址:http://blog.li ...

  6. 【转】掌握java枚举类型(enum type)

    原文网址:http://iaiai.iteye.com/blog/1843553 1   背景 在java语言中还没有引入枚举类型之前,表示枚举类型的常用模式是声明一组具有int常量.之前我们通常利用 ...

  7. 转载 java枚举类型enum的使用 (原文地址:http://blog.csdn.net/wgw335363240/article/details/6359614)

    java枚举类型enum的使用 最近跟同事讨论问题的时候,突然同事提到我们为什么java中定义的常量值不采用enmu枚举类型,而采用public final static 类型来定义呢?以前我们都是采 ...

  8. Java枚举类使用

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

  9. Java 枚举类型简介

    目录 Java 枚举示例 Java 枚举构造函数 枚举类型是用于定义常量集合的特殊类型,更确切的说,JAVA枚举类型是一种特殊的 java 类.枚举类型可以包含常量.方法等.在 java5 中添加了 ...

随机推荐

  1. 一、Spring的基本应用

    1.spring导包 导入maven包 <dependencies> <dependency> <groupId>org.springframework</g ...

  2. 30分钟闲置服务器建站(gitlab为例)

    前言 最近博主的阿里云主机又到了续费的时候了,刚买云主机的时候那是各种优惠各种打折,续费的时候只能当孙子了. 为了节省开支,又保证高性能的前提下,买了台10代NUC,内存和ssd自选,搭建一台个人服务 ...

  3. WIN10家庭版安装ORACLE的问题

    第一次安装成功后可启动ORACLE服务,重启计算机后服务监听无法启动,建议替换系统

  4. 简单解析PAT、PMT的程序

    刚开始学习有关TS.PAT.PMT方面的内容,参考了别人的一些程序,然后写了一个简单的解析TS的小程序.如果有地方错误,请发邮件给我843036544@qq.com. #include<stdi ...

  5. centos yum 安装golang

    rpm -Uvh http://dl.fedoraproject.org/pub/epel/6/x86_64/epel-release-6-8.noarch.rpm yum install golan ...

  6. Vue源码分析之实现一个简易版的Vue

    目标 参考 https://cn.vuejs.org/v2/guide/reactivity.html 使用 Typescript 编写简易版的 vue 实现数据的响应式和基本的视图渲染,以及双向绑定 ...

  7. 区块链入门到实战(12)之区块链 – 默克尔树(Merkle Tree)

    目的:解决由于区块链过长,导致节点硬盘存不下的问题. 方法:只需保留交易的哈希值. 区块链作为分布式账本,原则上网络中的每个节点都应包含整个区块链中全部区块,随着区块链越来越长,节点的硬盘有可能放不下 ...

  8. 初识ABP vNext(6):vue+ABP实现国际化

    Tips:本篇已加入系列文章阅读目录,可点击查看更多相关文章. 目录 前言 开始 语言选项 语言切换 注意 最后 前言 上一篇介绍了ABP扩展实体,并且在前端部分新增了身份认证管理和租户管理的菜单,在 ...

  9. [SCOI2013]摩托车交易 题解

    思路分析 为了让交易额尽量大,显然我们需要尽量多地买入.对于每个城市,到达这个城市时携带的黄金受到几个条件的影响:之前卖出的黄金,之前能买入的最多的黄金,前一个城市到当前城市的路径上的最小边权.既然不 ...

  10. JMeter尝鲜

    最近打算对一个线上HTTP接口做下压力测试,选择JMeter做为压测工具. 关于JMeter Apache JMeter是Apache组织开发的基于Java的压力测试工具.可以用于对静态的和动态的资源 ...