您好,欢迎来到网暖!

当前位置:网暖 » 站长资讯 » 建站基础 » 网络技术 » 文章详细 订阅RssFeed

Java枚举:小小enum,优雅而干净

来源:网络整理 浏览:290次 时间:2019-12-14

《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 高质量教学视频(已分门别类)。

推荐站点

  • 腾讯腾讯

    腾讯网(www.QQ.com)是中国浏览量最大的中文门户网站,是腾讯公司推出的集新闻信息、互动社区、娱乐产品和基础服务为一体的大型综合门户网站。腾讯网服务于全球华人用户,致力成为最具传播力和互动性,权威、主流、时尚的互联网媒体平台。通过强大的实时新闻和全面深入的信息资讯服务,为中国数以亿计的互联网用户提供富有创意的网上新生活。

    www.qq.com
  • 搜狐搜狐

    搜狐网是全球最大的中文门户网站,为用户提供24小时不间断的最新资讯,及搜索、邮件等网络服务。内容包括全球热点事件、突发新闻、时事评论、热播影视剧、体育赛事、行业动态、生活服务信息,以及论坛、博客、微博、我的搜狐等互动空间。

    www.sohu.com
  • 网易网易

    网易是中国领先的互联网技术公司,为用户提供免费邮箱、游戏、搜索引擎服务,开设新闻、娱乐、体育等30多个内容频道,及博客、视频、论坛等互动交流,网聚人的力量。

    www.163.com
  • 新浪新浪

    新浪网为全球用户24小时提供全面及时的中文资讯,内容覆盖国内外突发新闻事件、体坛赛事、娱乐时尚、产业资讯、实用信息等,设有新闻、体育、娱乐、财经、科技、房产、汽车等30多个内容频道,同时开设博客、视频、论坛等自由互动交流空间。

    www.sina.com.cn
  • 百度一下百度一下

    百度一下,你就知道

    www.baidu.com