《Java编程思想》中有这么一句话:“有时恰恰因为它,你才能够‘优雅而干净’地解决问题”——这句话说的是谁呢?就是本篇的主角——枚举(Enum)——大家鼓掌了。

在之前很长时间一段时间里,我都不怎么用枚举,因为总感觉它没什么用处——这其实就是“自我认知”的短见。当一个人一直蹲在自己的深井里而不敢跳出来的话,那他真的只能看到井口那么大点的天空

随着时间的推移,我做的项目越来越多,和枚举见面的机会也越来越多,于是我就渐渐地对它越来越有兴趣,研究得多了,才发现原来枚举如此的优秀。

1)枚举的常规用法

一个精简的枚举非常的干净优雅,见下例。

public enum Chenmo {
    WANGER, WANGSAN, WANGSI
}

我们为沉默枚举创建了三个值,分别是王二、王三、王四。这段代码实际上调用了3次Enum(String name, int ordinal)(ordinal单词的意思为顺序),也就是:

new Enum<Chenmo>("WANGER", 0);
new Enum<Chenmo>("WANGSAN", 1);
new Enum<Chenmo>("WANGSI", 2);

我们来遍历输出一下枚举:

for (Chenmo e : Chenmo.values()) {
    System.out.println(e);
}
//输出
//WANGER
//WANGSAN
//WANGSI

2)作为switch的判断条件

使用枚举作为switch语句判断条件能让我们的代码可读性更强,示例如下。

Chenmo key = Chenmo.WANGER;
switch (key) {
case WANGSI:
    System.out.println("今天我送出一个CSDN大鼠标垫");
    break;
case WANGSAN:
    System.out.println("今天我被坑一个CSDN学院年卡");
    break;
default:
    System.out.println("今天我一边高兴,一边失落");
    break;
}

在通过case关键字判断的时候,可以直接使用枚举值,非常简洁。另外,在编译期间限定类型,可以有效的避免越界的情况——字符串常量类型在作为switch判断条件的时候很容易因为误写而发生越界问题。

3)枚举实现单例

《Effective Java》一书中对使用枚举实现单例的方式推崇备至:

使用枚举实现单例的方法虽然还没有广泛采用,但是单元素的枚举类型已经成为实现Singleton的最佳方法。

我觉得“虽然还没有广泛采用”几个字可以去掉了,时至今日,大家应该都知道:使用枚举实现单例是一种非常好的方式。

先来看“双重校验锁”实现的单例:

public class SingleTon2 {

     // 私有化构造方法
    private SingleTon2() {
    };     private static volatile SingleTon2 singleTon = null;     public static SingleTon2 getInstance() {         // 第一次校验
        if (singleTon == null) {
            synchronized (SingleTon2.class) {
                // 第二次校验
                if (singleTon == null) {
                    singleTon = new SingleTon2();
                }
            }
        }
        return singleTon;
    }
}

再来看枚举实现的单例:

public enum SingleTon {

     INSTANCE;

    public void method() {
        System.out.println("我很快乐!");
    }
}

不比不知道,一比吓一跳啊!枚举方式的单例简单到爆——为了不至于看起来太过精简,我还加了一个输出“我很快乐”的方法。

枚举实现的单例可轻松地解决两个问题:

①、线程安全问题。因为Java虚拟机在加载枚举类的时候,会使用ClassLoader的loadClass方法,这个方法使用了同步代码块来保证线程安全。

②、避免反序列化破坏单例。因为枚举的反序列化并不通过反射实现。

4)枚举可与数据库交互

我们可以配合Mybatis将数据库字段转换为枚举类型。现在假设有一个数据库字段check_type的类型如下:

`check_type` int(1) DEFAULT NULL COMMENT '检查类型(1:未通过、2:通过)',

它对应的枚举类型为CheckType,代码如下:

public enum CheckType {
    NO_PASS(0, "未通过"), PASS(1, "通过");
    private int key;     private String text;     private CheckType(int key, String text) {
        this.key = key;
        this.text = text;
    }     public int getKey() {
        return key;
    }     public String getText() {
        return text;
    }     private static HashMap<Integer,CheckType> map = new HashMap<Integer,CheckType>();
    static {
        for(CheckType d : CheckType.values()){
            map.put(d.key, d);
        }
    }     public static CheckType parse(Integer index) {
        if(map.containsKey(index)){
            return map.get(index);
        }
        return null;
    }
}

CheckType枚举类比我们刚开始见到的那个Chenmo枚举类要复杂一些。

第一,CheckType新添加了构造方法,还有两个字段,key为int型,text为String型。

第二,CheckType中有一个public static CheckType parse(Integer index)方法,可将一个Integer通过key的匹配转化为枚举类型。

那么现在,我们可以在Mybatis的配置文件中使用typeHandler将数据库字段转化为枚举类型。

<resultMap id="CheckLog" type="com.entity.CheckLog">
  <id property="id" column="id"/>
  <result property="checkType" column="check_type" typeHandler="com.CheckTypeHandler"></result>
</resultMap>

其中checkType字段对应的类如下:

public class CheckLog implements Serializable {

    private String id;
    private CheckType checkType;     public String getId() {
        return id;
    }     public void setId(String id) {
        this.id = id;
    }     public CheckType getCheckType() {
        return checkType;
    }     public void setCheckType(CheckType checkType) {
        this.checkType = checkType;
    }
}

CheckTypeHandler转换器的类源码如下:

public class CheckTypeHandler extends BaseTypeHandler<CheckType> {

    @Override
    public CheckType getNullableResult(ResultSet rs, String index) throws SQLException {
        return CheckType.parse(rs.getInt(index));
    }     @Override
    public CheckType getNullableResult(ResultSet rs, int index) throws SQLException {
        return CheckType.parse(rs.getInt(index));
    }     @Override
    public CheckType getNullableResult(CallableStatement cs, int index) throws SQLException {
        return CheckType.parse(cs.getInt(index));
    }     @Override
    public void setNonNullParameter(PreparedStatement ps, int index, CheckType val, JdbcType arg3) throws SQLException {
        ps.setInt(index, val.getKey());
    }
}

CheckTypeHandler 的核心功能就是调用CheckType枚举类的parse()方法对数据库字段进行转换。

5)枚举会比静态常量更消耗内存吗?

说完枚举最常用的4个知识点后,我们来讨论一下“枚举会比静态常量更消耗内存吗?”这个话题——知乎上有人问这样的问题,还有很多人参与回答。

按我的理解,问这个问题的人就好像是在问“0.000,001”比“0.000,000,99”大吗?你说是吗?


上一篇:如果有人再问你 Java 的反射,把这篇文章扔给他

下一篇:Java注解(Annotation):请不要小看我!

微信搜索「沉默王二」公众号,关注后回复「免费视频」获取 500G 高质量教学视频(已分门别类)。

Java枚举:小小enum,优雅而干净的更多相关文章

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

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

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

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

  3. 深入理解Java枚举类型(enum)

    https://blog.csdn.net/javazejian/article/details/71333103 深入理解Java类型信息(Class对象)与反射机制 深入理解Java枚举类型(en ...

  4. Java 枚举(enum)的学习

    Java 枚举(enum)的学习 本文转自:https://blog.csdn.net/javazejian/article/details/71333103 枚举的定义 在定义枚举类型时我们使用的关 ...

  5. Java枚举类型enum使用详解

      java的Enum枚举类型终于在j2se1.5出现了.之前觉得它只不过是鸡肋而已,可有可无.毕竟这么多年来,没有它,大家不都过得很好吗?今日看<Thinking in Java>4th ...

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

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

  7. Java枚举类enum

    枚举类enum是JDK1.5引入的,之前都是用public static final int enum_value来代替枚举类的.枚举类enum是一种特殊的类,它默认继承了类java.lang.Enu ...

  8. java枚举学习enum

    java 1.5以后才出现enum的关键字 所有的enum类都继承自Enum类,所以enum类无法再继承其他的类,可以实现接口,枚举类出了不能被继承其余的与普通类的特性一致, 枚举类的构造函数只能自己 ...

  9. Java 枚举(enum)详解

    概念: Java1.5发行版本中增加了新的引用类型--枚举类型(enum type).枚举类型是指由一组固定的常量组成合法值的类型.在Java虚拟机中,枚举类在进行编译时会转变成普通的Java类. 创 ...

  10. java 枚举类 enum 总结

    枚举定义: enum是计算机编程语言中的一种数据类型.枚举类型:在实际问题中,有些变量的取值被限定在一个有限的范围内.例如,一个星期内只有七天,一年只有十二个月,一个班每周有六门课程等等.如果把这些量 ...

随机推荐

  1. 关于基线baseline及与inline-block、vertical-aline等属性的关系(完善中.......)

    1. 基本含义 基线(base line):而是英文字母x的下端沿,是a,c,z,x等字母的底边线,并不是汉字文字的下端沿,.下图的红色线即为基线.凡是涉及到垂直方向的排版或者对齐的,都离不开最最基本 ...

  2. 跟我学ASP.NET MVC之三:完整的ASP.NET MVC程序-PartyInvites

    摘要: 在这篇文章中,我将在一个例子中实际地展示MVC. 场景 假设一个朋友决定举办一个新年晚会,她邀请我创建一个用来邀请朋友参加晚会的WEB程序.她提出了四个注意的需求: 一个首页展示这个晚会 一个 ...

  3. CentOS 7.2 关闭防火墙

    CentOS7 的防火墙配置跟以前版本有很大区别,CentOS7这个版本的防火墙默认使用的是firewall,与之前的版本使用iptables不一样 1.关闭防火墙: systemctl stop f ...

  4. Python实现控制台密码星号输入

    import msvcrt, sys, os print('password: ', end='', flush=True) li = [] while 1: ch = msvcrt.getch() ...

  5. Linux用户和组管理,添加修改用户,添加修改组,加入组,移除组

    1.安全介绍3A Authentication: 认证,用户名和对应口令 Authorization: 授权,不同用户权限不同 Accouting/Audition: 审计 2. 所属者和所属组 us ...

  6. bzoj 1485 [HNOI2009]有趣的数列 卡特兰数

    把排好序的序列看成一对对括号,要把他们往原数列里塞,所以就是括号序合法方案数 即为卡特兰数 f(n)=Cn2nn+1 求的时候为避免除法,可以O(n)计算每个素数出现次数,最后乘起来,打完之后发现其实 ...

  7. jenkins+docker 持续构建非docker in docker

    工欲善其事必先利其器,为了解脱程序员的,我们程序员本身发明了很多好用的工具,通过各种工具的组合来达到我们想要的结果 本文采用jenkins docker svn maven作为相关工具,项目sprin ...

  8. (2)STM32使用HAL库操作外部中断——理论讲解

    1.中断触发过程 对主程序压栈--把中断服务函数的地址写入到程序计数器(PC)--执行中断服务函数 2.中断向量表 中断服务函数的地址在STM32的手册上的中断向量表中(如下是一部分): 如上表所示, ...

  9. mysql报错mmap(137428992 bytes) failed; errno 12,Cannot allocate memory for the buffer pool

    mysql以`systemctl start mysqld.service`的方式启动一段时间后发现突然无法启动,尝试重新启动也不能解决问题,排查问题时,先后通过`systemctl status m ...

  10. .NET Core Dapper操作mysql数据库

    前言 现在ORM盛行,市面上已经出现了N款不同的ORM套餐了.今天,我们不谈EF,也不聊神马黑马,就说说 Dapper.如何在.NET Core中使用Dapper操作Mysql数据库呢,让我们跟随镜头 ...