什么是枚举

枚举是java5中新增的特性,他是一个特殊的数据类型,他的特殊性在于他既是一种类类型,又比类类型多了安全性,简洁性,便捷性。java枚举类型是功能十分强大齐全的类,功能比其他语言中的对等物要强大的多,java的枚举类型本质上是int值。

java枚举类型背后的基本想法:就是通过共有的静态final域为每个枚举常量导出实例的类,因为没有可以访问的构造器,所以枚举类型是真正的final。枚举天生是不可变的。

枚举基本实现

首先来看看我们在项目中不使用枚举声明一段int类型的常量。

/** 订单状态 0:未支付*/
public static final int ORDER_DEPOT_UNPAY = 0; /** 订单状态 1:已支付*/
public static final int ORDER_DEPOT_PAID = 1; /** 订单状态 2:支付超时*/
public static final int ORDER_DEPOT_TIMEOUT = 2; /** 物流状态 0:物流状态*/
public static final int ORDER_LOGISTICS_READY = 0; /** 物流状态 1:物流中*/
public static final int ORDER_LOGISTICS_TRANSPORT = 1; /** 物流状态 2:已收货*/
public static final int ORDER_LOGISTICS_ARRIVED = 2;

这种方法被称为int枚举模式,我们可以看到对于每一种订单状态需要以ORDER_DEPOT作为前缀,如果当出现有多个int值具有相同的值时,前缀可以防止名称发生冲突。

采用int枚举模式的程序是十分脆弱的,因为int枚举是编译时常量,被编译到使用它们的客户端中。如果与枚举常量关联的int发生了变化,客户端就必须要重新编译。如果没有重新编译,程序还是可以运行,但是他们的行为是不确定的。

像这种我们就可以直接使用一下这种最简单的形式:

/** 订单状态枚举类*/
public enum DepotEnum{
UNPAY,PAID,TIMEOUT;
} /** 物流订单状态枚举类*/
public enum LogisticsEnum{
READY,TRANSPORT,ARRIVED;
} public static void main (String[] args) {
System.out.println (DepotEnum.UNPAY.ordinal ());
System.out.println (LogisticsEnum.ARRIVED.ordinal ());
}

上面这个也能达到相同的效果。许多枚举天生就与一个单独的int值想关联,所有的枚举都有一个ordinal方法,它返回每个枚举常量在类型中的数字位置。

枚举类型与数据库字段交互

comment on column ORDER.PAY_STATE is '字符状态(0:未支付、1:已支付、2:支付超时)';

我们在数据库中经常会有这种状态的字段,像这种如果不在界面上需要展示的话,要么在sql中使用decode函数,要么在前端使用if else 判断。所以我们可以使用一个EnumMap来存取这样的对象。EnumMap时一个用于存储key为枚举类型的map,底层使用数组实现。

public class OrderEnumMap {
/**
* 定义一个基本的枚举类型
*/
public enum BaseEnumMap{
/**未支付*/
UNPAY,
/**已支付*/
PAID,
/**支付超时*/
TIMEOUT;
} /**声明枚举map*/
private EnumMap<BaseEnumMap,String> enumMap = new EnumMap<BaseEnumMap,String>(BaseEnumMap.class); public OrderEnumMap(){
enumMap.put(BaseEnumMap.UNPAY,"未支付");
enumMap.put(BaseEnumMap.PAID,"已支付");
enumMap.put(BaseEnumMap.TIMEOUT,"支付超时");
} /**
* 获取支付状态
* @param code
* @return
*/
public String getOrderState(int code){
if(BaseEnumMap.class.getEnumConstants().length > code) {
return this.enumMap.get(BaseEnumMap.class.getEnumConstants()[code]);
}
return null;
} public static void main(String[] args) {
System.out.println(new OrderEnumMap().getOrderState(2));
}
}

还有另外一种方式:

/**
* 订单状态枚举类
*/
public enum OrderEnum{
/** 标识订单的未支付状态*/
UNPAY("未支付",0),
/** 标识订单的已支付状态*/
PAID("已支付",1),
/** 标识订单的支付超时状态*/
TIMEOUT("支付超时",2); /**描述*/
private String desc; /**编码*/
private int code; OrderEnum (String desc, int code) {
this.desc = desc;
this.code = code;
} private static HashMap<Integer,String> map = new HashMap<Integer,String>();
static {
for (OrderEnum d : OrderEnum.values ()) {
map.put (d.code, d.desc);
}
} public static String getDescByCode(int code){
if(map.containsKey (code)){
return map.get (code);
}
return null;
}
}
public static void main(String[] args) {
System.out.println(OrderEnum.getDescByCode(1));
}

个人认为方式二会更优一点,尽量不要写内部枚举类。

枚举实现单例

《Effective Java》一书中对使用枚举实现单例的方式推崇备至:使用枚举实现单例的方法虽然还没有广泛采用,但是单元素的枚举类型已经成为实现Singleton的最佳方法。

使用枚举类创建单例的有点在于:线程安全,调用效率高,不能延时加载,可以天然的防止反射和反序列化调用。

来对比一下普通的单例和使用枚举实现的单例:

/**
* 普通的单例(饿汉式)
*/
public class Singleton{
private static Singleton instance = new Singleton;
private Singleton(){}
public static Singleton getInstance(){
return instance;
}
public void doSomeThing(){
System.out.println ("实现单例的方法是声明-普通单例类");
}
}
/**
* 枚举单例
*/
public enum SingletonEnum {
Singleton;
public void doSomeThing(){
System.out.println ("实现单例的方法是声明-枚举类");
}
}

枚举实现单例的线程安全

枚举的底层是依赖Enum类实现的,这个类的成员变量都是static类型的,并且在静态代码块中被实例化的,和饿汉模式有点像,所以他是天然线程安全的。

枚举和行为绑定

与枚举常量有关的有些行为,可能指需要用在定义了枚举的类或者包中,这种行为最好被实现成私有的或者包级私有的方法。每个常量都关联了不同的数据,本质上将不同的行为与每个常量关联起来。来看看计算器的四大基本操作:

public class Operate {
public enum NormalActive {
PLUS, MINUS, MULIT, DIVIDS, DIFFER; double oper (double x, double y) {
switch (this) {
case PLUS:
return x + y;
case MINUS:
return x - y;
case MULIT:
return x * y;
case DIVIDS:
return x / y;
case DIFFER:
return (x + 1) * y;
default:
throw new AssertionError();
}
}
} public static void main (String[] args) {
System.out.println (NormalActive.PLUS.oper (2, 3));
}
}

上面这段代码可以执行,但是还不够好,如果没有throw语句的话,就不能通过编译。同时,这段代码也很脆弱,如果添加了新的枚举常量,却没有在switch种添加相应的条件,编译可以通过,但是执行却会报错。

那么更好的方法是,在枚举类型中声明一个抽象的方法。并在特定于常量的类主体中。

/**
* 更好的实现枚举的加,减,乘,除
*/
public enum BetterEnum{ PLUS{
@Override
public double calc(double x,double y){
return x+y;
}
},
MINUS{
@Override
double calc (double x, double y) {
return x - y;
}
},
MULTI{
@Override
double calc (double x, double y) {
return x * y;
}
},
DIVIDS{
@Override
double calc (double x, double y) {
return x / y;
}
}; abstract double calc(double x,double y);
}

枚举实现策略模式

public enum StrategyEnum {

    MONDAY (PayType.WORK), TUESDAY (PayType.WORK),
WEDNESDAY (PayType.WORK), THURSDAY (PayType.WORK),
FRIDAY (PayType.WORK), SATURDAY (PayType.REST),
SUNDAY (PayType.REST); private final PayType payType; /**
* 构造器
*
* @param payType 支付类型
*/
StrategyEnum (PayType payType) {
this.payType = payType;
} double pay(double workTime){
return payType.pay (workTime);
} /**
* 内部枚举类,计算加班费
*/
public enum PayType {
WORK {
@Override
double pay (double workTime) {
return workTime * HOURS_WORK;
}
}, REST {
@Override
double pay (double workTime) {
return workTime * HOURS_REST;
}
}; /**
* 工作日每小时加班费
*/
private static final int HOURS_WORK = 200; /**
* 休息日每小时加班费
*/
private static final int HOURS_REST = 300; abstract double pay (double workTime); } public static void main (String[] args) {
System.out.println (StrategyEnum.THURSDAY.pay (2.5));
} }

本文部分摘自《Effective Java》一书,仅作记录。如果想要深入了解enum类型,可以查看大佬的这篇博客:

https://blog.csdn.net/javazejian/article/details/71333103

简单认识java enum枚举的更多相关文章

  1. Java enum枚举类型

    java的枚举类型详解: 简单示例: public enum Color{ RED,BLUE,BLACK,YELLOW,GREEN } 复杂示例(带自定义构造方法与类型) public enum En ...

  2. (转)java enum枚举

    转载自: 原理:http://singleant.iteye.com/blog/686349 应用:http://www.cnblogs.com/happyPawpaw/archive/2013/04 ...

  3. Java Enum枚举的用法(转)

    说明:Java的枚举比dotnet的枚举好用,至少支持的方式有很多. 用法一:常量 在JDK1.5 之前,我们定义常量都是: public static fianl.... .现在好了,有了枚举,可以 ...

  4. 161208、Java enum 枚举还可以这么用

    在大部分编程语言中,枚举类型都会是一种常用而又必不可少的数据类型,Java中当然也不会例外.然而,Java中的Enum枚举类型却有着许多你意想不到的用法,下面让我们一起来看看. 先来看一段代码示例: ...

  5. Java Enum枚举 遍历判断 四种方式(包括 Lambda 表达式过滤)

    示例代码如下: package com.miracle.luna.lambda; import java.util.Arrays; /** * @Author Miracle Luna * @Date ...

  6. Java Enum 枚举的简单使用

    一.什么是枚举 值类型的一种特殊形式,它从 System.Enum 继承,并为基础基元类型的值提供备用名称.枚举类型有名称.基础类型和一组字段.基础类型必须是一个内置的有符号(或无符号)整数类型(如 ...

  7. Java enum(枚举)的用法详解(转)

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

  8. 简单看看java之枚举

    枚举类这个类用的比较少,对这个不怎么熟悉,最近看源码刚好可以好好了解一下,那么,枚举Enum是什么呢?在jdk中,Enum是一个抽象类下图所示,这就说明这个类是不能进行实例化的,那么我们应该怎么使用呢 ...

  9. Java enum枚举在实际项目中的常用方法

    在项目实际开发过程中,经常会遇到对某些固定的值.字典项的定义的需求,很多项目经常使用常量来定义,其实在jdk1.5就已经引入了枚举,使用枚举可以更好的解决这类需求,本文主要记录枚举的优势以及经常在项目 ...

随机推荐

  1. 布客&#183;ApacheCN 编程/大数据/数据科学/人工智能学习资源 2020.2

    特约赞助商 公告 我们愿意普及区块链技术,但前提是互利互惠.我们有大量技术类学习资源,也有大量的人需要这些资源.如果能借助区块链技术存储和分发,我们就能将它们普及给我们的受众. 我们正在招募项目负责人 ...

  2. Spring学习六:自定义Event事件

    Spring 中的自定义事件 编写和发布自己的自定义事件有许多步骤.按照在这一章给出的说明来编写,发布和处理自定义 Spring 事件. 步骤 描述 1 创建一个名称为 SpringExample 的 ...

  3. cookie、session、jsession 关系

    感谢大佬:https://www.cnblogs.com/fsjin/articles/3490531.html 在使用CAS的时候,对Cookies.session.jsession 这三者是什么不 ...

  4. Visual Studio 下error C2471: 无法更新程序数据库

    转载请注明来源:https://www.cnblogs.com/hookjc/ 解决方案:修改项目属性 右击项目 --> "属性" 1. "C/C++" ...

  5. python办公自动化系列之金蝶K3自动登录(二)

    接上一篇博文python办公自动化系列之金蝶K3自动登录(一),我们接着聊聊利用python脚本实现金蝶K3 Wise客户端自动登录这一需求. 如上图所示,自动选择[组织机构]后,我们还需要驱动[当前 ...

  6. MySQL 主从复制与读写分离 (超详细图文并茂小白闭着眼睛都会做)

    MySQL 主从复制与读写分离 1.什么是读写分离 2.为什么要读写分离 3.什么时候要读写分离 4.主从复制与读写分离 5.mysql支持的复制类型 6.主从复制的工作过程 7.MySQL主从复制延 ...

  7. 帆软报表(finereport)点击事件对话框打开

    点击事件对话框打开iframe var iframe = $("<iframe id='001' name='001' width='100%' height='100%' scrol ...

  8. 手把手教你实现pynq-z2条形码识别

    我是 雪天鱼,一名FPGA爱好者,研究方向是FPGA架构探索和SOC设计. 关注公众号,拉你进"IC设计交流群". 1.前言 单单实现一个二维码识别就花了将近一个星期,这篇文章我就 ...

  9. 4、网络并发编程--僵尸进程、孤儿进程、守护进程、互斥锁、消息队列、IPC机制、生产者消费者模型、线程理论与实操

    昨日内容回顾 操作系统发展史 1.穿孔卡片 CPU利用率极低 2.联机批处理系统 CPU效率有所提升 3.脱机批处理系统 CPU效率极大提升(现代计算机雏形) 多道技术(单核CPU) 串行:多个任务依 ...

  10. OSI七层协议&TCP协议(三次握手四次挥手)

    今日内容 python 基础回顾 软件开发架构 网络理论前戏 OSI 七层协议(五层) TCP协议 三次握手与四次挥手 UDP协议 内容详细 一.python 基础回顾 1.基本数据类型 整型 int ...