Java——枚舉:優雅而乾淨的enum

←←←←←←←←←←←← 快!點關注數據庫

《Java編程思想》中有這麼一句話:「有時偏偏由於它,你纔可以‘優雅而乾淨’地解決問題」——這句話說的是誰呢?就是本篇的主角——枚舉(Enum)——你們鼓掌了。編程

在以前很長時間一段時間裏,我都不怎麼用枚舉,由於總感受它沒什麼用處——這其實就是「自我認知」的短見。當一我的一直蹲在本身的深井裏而不敢跳出來的話,那他真的只能看到井口那麼大點的天空安全

隨着時間的推移,我作的項目愈來愈多,和枚舉見面的機會也愈來愈多,因而我就漸漸地對它愈來愈有興趣,研究得多了,才發現原來枚舉如此的優秀。ide

1、枚舉的常規用法

一個精簡的枚舉很是的乾淨優雅,見下例。this

public enum Chenmo {
    WANGER, WANGSAN, WANGSI
}

咱們爲沉默枚舉建立了三個值,分別是王2、王3、王四。這段代碼實際上調用了3次Enum(String name, int ordinal)(ordinal單詞的意思爲順序),也就是:spa

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語句判斷條件能讓咱們的代碼可讀性更強,示例以下。code

···
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;

}
···rem

在經過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("我很快樂!");
    }
}

不比不知道,一比嚇一跳啊!枚舉方式的單例簡單到爆——爲了避免至於看起來太過精簡,我還加了一個輸出「我很快樂」的方法。

枚舉實現的單例可輕鬆地解決兩個問題:

  1. 線程安全問題。由於Java虛擬機在加載枚舉類的時候,會使用ClassLoader的loadClass方法,這個方法使用了同步代碼塊來保證線程安全。
  2. 避免反序列化破壞單例。由於枚舉的反序列化並不經過反射實現。

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」大嗎?你說是嗎?

相關文章
相關標籤/搜索