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

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

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

1)枚举的常规用法

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

  1. public enum Chenmo {
        WANGER, WANGSAN, WANGSI
    }

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

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

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

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

2)作为switch的判断条件

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

  1. 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的最佳方法。

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

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

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

再来看枚举实现的单例:

  1. public enum SingleTon {
  2.      INSTANCE;
  3.     public void method() {
            System.out.println("我很快乐!");
        }
    }

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

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

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

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

4)枚举可与数据库交互

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

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

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

  1. public enum CheckType {
        NO_PASS(0, "未通过"), PASS(1, "通过");
        private int key;
  2.     private String text;
  3.     private CheckType(int key, String text) {
            this.key = key;
            this.text = text;
        }
  4.     public int getKey() {
            return key;
        }
  5.     public String getText() {
            return text;
        }
  6.     private static HashMap<Integer,CheckType> map = new HashMap<Integer,CheckType>();
        static {
            for(CheckType d : CheckType.values()){
                map.put(d.key, d);
            }
        }
  7.     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将数据库字段转化为枚举类型。

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

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

  1. public class CheckLog implements Serializable {
  2.     private String id;
        private CheckType checkType;
  3.     public String getId() {
            return id;
        }
  4.     public void setId(String id) {
            this.id = id;
        }
  5.     public CheckType getCheckType() {
            return checkType;
        }
  6.     public void setCheckType(CheckType checkType) {
            this.checkType = checkType;
        }
    }

CheckTypeHandler转换器的类源码如下:

  1. public class CheckTypeHandler extends BaseTypeHandler<CheckType> {
  2.     @Override
        public CheckType getNullableResult(ResultSet rs, String index) throws SQLException {
            return CheckType.parse(rs.getInt(index));
        }
  3.     @Override
        public CheckType getNullableResult(ResultSet rs, int index) throws SQLException {
            return CheckType.parse(rs.getInt(index));
        }
  4.     @Override
        public CheckType getNullableResult(CallableStatement cs, int index) throws SQLException {
            return CheckType.parse(cs.getInt(index));
        }
  5.     @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. 1.用互联网的产品思维打造一本app后端的书

    刚刚接触app后端,是做完adidas中国的官方商城的时候,那时不清楚app后端应该怎么架构,只能摸着石头过河,网络上只有一些零散的资料,遇到问题,只能不断地搜索,思考,务必找到解决问题的方法. 在从 ...

  2. Guava新增集合类型-Multiset

    Guava新增集合类型-Multiset Guava引进了JDK里没有的,但是非常有用的一些新的集合类型.所有这些新集合类型都能和JDK里的集合平滑集成.Guava集合非常精准地实现了JDK定义的接口 ...

  3. 在C++遇到有些关键字或者函数被弃用的情况

    随着每一次C++的不断更新,可能都会有些函数或者关键字会被弃用,或者换成了其他的名字,这在编写代码的时候经常会碰到,碰到这种情况,可以在代码的第一行写上忽略此错误的句子,一般为: #pragma  w ...

  4. [Poi2012]A Horrible Poem BZOJ2795

    分析: 这是今天下午的考试题,推了2个小时,考试中A掉了 首先,循环串通过字符串hash可以O(1)判断:get_hash(l,r-len)==get_hash(l+len,r);显然可证. 我们其次 ...

  5. BZOJ_1774_[Usaco2009 Dec]Toll 过路费_floyd

    BZOJ_1774_[Usaco2009 Dec]Toll 过路费_floyd 题意: 跟所有人一样,农夫约翰以着宁教我负天下牛,休叫天下牛负我的伟大精神,日日夜夜苦思生 财之道.为了发财,他设置了一 ...

  6. Spring 系列之Spring常用注解总结

    传统的Spring做法是使用.xml文件来对bean进行注入或者是配置aop.实物,这么做有两个缺点: 1.如果所有的内容都配置在.xml文件中,那么.xml文件将会十分庞大:如果按需求分开.xml文 ...

  7. C#之Socket的简单使用

    Socket是一种通信TCP/IP的通讯接口,也就是HTTP的抽象层,就是Socket在Http之上,Socket也就是发动机.实际上,传输层的TCP是基于网络层的IP协议的,而应用层的HTTP协议又 ...

  8. 游戏AI之初步介绍(0)

    目录 游戏AI是什么? 游戏AI和理论AI 智能的假象 (更新)游戏AI和机器学习 介绍一些游戏AI 4X游戏AI <求生之路>系列 角色扮演/沙盒游戏中的NPC 游戏AI 需要学些什么? ...

  9. 8天入门docker系列 —— 第一天 docker出现前的困惑和简单介绍

    docker出来也有很多年了,但用到的公司其实并不是很多,docker对传统开发是一个革命性的,几乎颠覆了之前我们传统的开发方法和部署模式,而大多 公司保守起见或不到万不得已基本上不会去变更现有模式. ...

  10. DSAPI 网页获取本地程序登陆用户

    这是一个非常简单的示例,在网页或其他平台获取程序中已经登陆的用户,当然也可以是其他信息. 源码 Imports DSAPI.网络.HTTP监听_DSWebAPI Public Class Form1 ...