Java 枚舉(enum)剖析

目錄

Java 枚舉(enum)概述

枚舉常量

屬性與方法

枚舉參數

實現接口

抽象方法


Java 枚舉(enum)概述

1、Java JDK 1.5 新增的 enum 關鍵詞,可以定義枚舉類,如 public enum WeekEnum { }.

2、使用 enum 定義後的枚舉類在編譯後默認繼承 java.lang.Enum 類,而不是普通的繼承 Object 類。由於 Java 不支持多繼承,所以枚舉不能再顯示的繼承其他類,但是可以實現接口。

3、Enum 類默認實現了 Java.lang.Comparable 接口與 Serializable 接口

4、Enum 類重寫了 toString 方法,返回聲明中包含的此枚舉常量的名稱。

5、enum 聲明後,該類會被編譯器加上 final 聲明(如同 String),故枚舉無法被繼承。

6、枚舉類內部定義的枚舉值就是該類的實例,且必須在第一行定義,當類初始化時,這些枚舉值會被實例化,互相以逗號分隔。 如 "Monday, Tuesday, Wednesday, Thursday, Friday, Saturday, Sunday"

7、每個枚舉類都有一個 values 方法,該方法可以遍歷枚舉類的所有實例.

8、枚舉規定好了指定的取值範圍,所有的內容只能從指定的範圍中取得。

9、枚舉是一種類型,用於定義變量,以限制變量的賦值;通過 "枚舉名.值" 取得枚舉值,每個值都是一個 Enum 實例

10、枚舉是一個特殊的類,可以定義自己的 field、方法、可以實現接口,也可以定義自己的構造器.

11、枚舉類的構造方法默認用 private 修飾的,且不能出現 public 構造方法,因此無法 new 一個枚舉對

13、實際編程中往往存在着這樣的 "數據集",它們的數值是穩定的、元素個數是有限的,例如星期一到星期日,春夏秋冬四季等等,很多時候大家選擇使用常量。 JDK 1.5 開始有了枚舉,其實可以把相關的常量放到一個枚舉類型裏,枚舉提供了比常量更多的方法,使用起來更加方便。

枚舉常量

1、定義枚舉

/**
 * 星期,一週的枚舉
 */
public enum WeekEnum {
    /**
     * 最簡單的枚舉形式,使用逗號分隔,結尾分號此時可以省略
     * 每一個值都代表當前的枚舉實例,通過 枚舉名.值 獲取
     */
    Monday, Tuesday, Wednesday, Thursday, Friday, Saturday, Sunday
}

2、測試枚舉:

import wmx.com.springboothello.enum_wmx.WeekEnum;
public class Test {
    public static void main(String[] args) {
        //類似靜態類,也是 枚舉名.值 直接獲取,每個值都是 Enum 實例
        WeekEnum sundayEnum = WeekEnum.Sunday;
        //因爲 Enum 重寫了 toString 方法,方法中返回 name 屬性
        System.out.println("WeekEnum.Sunday=" + sundayEnum.toString());//輸出 Sunday
        //返回此枚舉常量的名稱,與其枚舉聲明中聲明的完全相同,看源碼一目瞭然
        System.out.println("weekEnum.name()=" + sundayEnum.name());//輸出 Sunday
        switch (sundayEnum) {
            case Monday:
                System.out.println("星期1");
                break;
            case Friday:
                System.out.println("星期5");
                break;
            case Sunday:
                System.out.println("星期7");//會輸出
        }
        //每個枚舉類都有一個 values 方法,可以遍歷枚舉類的所有 Enum 實例.
        WeekEnum[] weekEnums = WeekEnum.values();
        for (WeekEnum weekEnum_loop : weekEnums) {
            //ordinal():返回此枚舉常數的序號(就是在枚舉聲明中的位置,從0開始)。
            System.out.print(weekEnum_loop.ordinal() + ":" + weekEnum_loop.name() + "  ");
        }

        /**
         * compareTo:看源碼一目瞭然,就是根據序號 ordinal 對比同類型的枚舉值是否相等
         * 自己的序號減去對比項的序號,如果爲0則相等,否則就是正負數。注意只能對比相同枚舉類型
         */
        WeekEnum mondayEnum = WeekEnum.Monday;
        int flag1 = sundayEnum.compareTo(mondayEnum);
        int flag2 = sundayEnum.compareTo(WeekEnum.Sunday);
        System.out.println("\n" + flag1 + "、" + flag2);//輸出 6、0
    }
}

屬性與方法

1、枚舉像普通的類一樣可以添加屬性和方法(包括靜態或非靜態的屬性或方法)。注意枚舉值要寫在最前面,且以分號結尾,否則編譯出錯。

/**
 * 星期,一週的枚舉
 */
public enum WeekEnum {
    //枚舉值寫在最前面,有其他內容時,必須以分號結尾
    Monday, Tuesday, Wednesday, Thursday, Friday, Saturday, Sunday;
    //枚舉對象得通過上面得值來獲取,其餘得編碼和普通的 類 區別不大
    private Integer id;
    public static String summary;

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }
}

2、測試代碼:

import wmx.com.springboothello.enum_wmx.WeekEnum;
public class Test {
    public static void main(String[] args) {
        //枚舉名.值 獲取實例。獲取到實例後,其餘得編碼和普通的 類 區別不大
        WeekEnum sundayEnum = WeekEnum.Sunday;

        Integer id = sundayEnum.getId();//此時因爲屬性沒有賦值,所以輸出:null、null
        System.out.println(id + "、" + WeekEnum.summary);

        sundayEnum.setId(9527);//給id屬性賦值
        id = sundayEnum.getId();//重新取值
        WeekEnum.summary = "梅山龍宮";//爲靜態屬性賦值。如果枚舉中有靜態方法,則也是同理 枚舉枚舉名.靜態方法名
        System.out.println(id + "、" + WeekEnum.summary);//輸出:9527、梅山龍宮
    }
}

枚舉參數

1、枚舉常量後面可以接括號定義枚舉參數,這些參數會通過對應的構造器自動給屬性賦值。"枚舉參數 -> 對應的構造器 -> 屬性" 完成賦值

/**
 * 星期,一週的枚舉
 */
public enum WeekEnum {
    //枚舉值寫在最前面,有其他內容時,必須以分號結尾。
    //因爲枚舉只能通過常量獲取枚舉實例,所以枚舉參數必須與構造器中的參數對應
    Monday(1, "星期一"),//匹配兩個參數的構造器創建實例
    Tuesday(2, "星期二"),
    Wednesday(3, "星期三"),
    Thursday(4, "星期四"),
    Friday(5, "星期五"),
    Saturday(6, "星期六"),
    Sunday(7, "星期天", "週末");//匹配三個參數的構造器創建實例

    //屬性名稱可以隨便取,但是構造器中的參數類型必須與上面的枚舉參數類型對應
    private Integer code;
    private String name;
    private String ext;

    //構造器默認是 private ,外部無法 new 枚舉對象,只能通過上面的常量獲取實例,必須與枚舉參數對應
    WeekEnum(Integer code, String name) {
        this.code = code;
        this.name = name;
    }

    WeekEnum(Integer code, String name, String ext) {
        this.code = code;
        this.name = name;
        this.ext = ext;
    }

    //因爲枚舉常量的參數都是通過內部私有的構造器賦值的,無法通過外部賦值,所以沒必要提供 setter方法
    //但是可以提供 getter 方法來獲取枚舉參數值
    public Integer getCode() {
        return code;
    }

    public String getName() {
        return name;
    }

    public String getExt() {
        return ext;
    }
}

2、測試代碼:

import wmx.com.springboothello.enum_wmx.WeekEnum;
public class Test {
    public static void main(String[] args) {
        //枚舉名.值 獲取實例,這些值之所以叫枚舉常量,因爲它的值就如同常量一樣一開始就頂死了的,無法修改
        WeekEnum sundayEnum = WeekEnum.Sunday;
        WeekEnum mondayEnum = WeekEnum.Monday;
        //上面的實例包含了自己枚舉參數,所以可以通過 getter 方法獲取
        System.out.println(sundayEnum.getCode() + "->" + sundayEnum.getName() + "->" + sundayEnum.getExt());
        System.out.println(mondayEnum.getCode() + "->" + mondayEnum.getName() + "->" + mondayEnum.getExt());
        //輸出:7->星期天->週末
        //輸出:1->星期一->null。因爲星期一沒有提供 ext 參數,所以爲 null
    }
}

2、總結:

枚舉的構造器私有,每一個枚舉值都是一個枚舉實例,編譯後自動產生。枚舉值的參數與構造器的參數相對應,即枚舉值後面沒跟參數時,構造器也是無參構造,
枚舉值後面跟參數時,必須要有參數個數且類型相同的構造器與之對應,以及設置相應的成員變量。

編譯構建實例的順序是:枚舉值後面的實參值->找到對應的構造方法->注入給相應的成員變量。因爲構造器可以重載,所以枚舉值後面的參數可以不同,包括類型與個數。
每個枚舉值既可以調用自己獨有的屬性,即後面的參數值,也可以調用公共的屬性,即可調用自己下面獨有的方法,也可調用公共的方法。

當枚舉值/枚舉常量沒有帶參數時,則沒必要要構造器,反之如果枚舉值有參數,則必須有構造器與之對應

實現接口

1、先準備一個接口:

import java.util.Map;
public interface WeekEnumInterface {
    Integer getCode();
    String getName();
    Map<String, Object> getDataMap();
}

2、定義枚舉並實現接口

import java.util.HashMap;
import java.util.Map;
/**
 * 星期,一週的枚舉
 * 枚舉 enum 默認已經繼承了 Enum 類,所以無法再繼承,但是可以實現接口
 */
public enum WeekEnum implements WeekEnumInterface {
    //枚舉值寫在最前面,有其他內容時,必須以分號結尾。
    //因爲枚舉只能通過常量獲取枚舉實例,所以枚舉參數必須與構造器中的參數對應
    Monday(1, "星期一"),//匹配兩個參數的構造器創建實例
    Tuesday(2, "星期二"),
    Wednesday(3, "星期三"),
    Thursday(4, "星期四"),
    Friday(5, "星期五"),
    Saturday(6, "星期六"),
    Sunday(7, "星期天");

    //屬性名稱可以隨便取,但是構造器中的參數類型必須與上面的枚舉參數類型對應
    private Integer code;
    private String name;

    //構造器默認是 private ,外部無法 new 枚舉對象,只能通過上面的常量獲取實例,必須與枚舉參數對應
    WeekEnum(Integer code, String name) {
        this.code = code;
        this.name = name;
    }

    @Override
    public Integer getCode() {
        return code;
    }

    @Override
    public String getName() {
        return name;
    }

    //將整個枚舉參數轉爲 Map 結構
    @Override
    public Map<String, Object> getDataMap() {
        Map<String, Object> dataMap = new HashMap<>(WeekEnum.values().length);
        for (WeekEnum weekEnum : WeekEnum.values()) {
            dataMap.put(weekEnum.code + "", weekEnum.name);
        }
        return dataMap;
    }
}

3、測試代碼:

import wmx.com.springboothello.enum_wmx.WeekEnum;
import java.util.Map;
public class Test {
    public static void main(String[] args) {
        //枚舉名.值 獲取實例,這些值之所以叫枚舉常量,因爲它的值就如同常量一樣一開始就頂死了的,無法修改
        WeekEnum sundayEnum = WeekEnum.Sunday;
        System.out.println(sundayEnum.getCode() + " - " + sundayEnum.getName());
        //
        Map<String, Object> dataMap = sundayEnum.getDataMap();
        for (Map.Entry<String, Object> entry : dataMap.entrySet()) {
            System.out.println(entry.getKey() + " = " + entry.getValue());
        }
    }
}

抽象方法

1、枚舉中可以有抽象方法,且由枚舉值/枚舉常量提供方法實現。枚舉類如下:

/**
 * 星期,一週的枚舉
 * 枚舉 enum 默認已經繼承了 Enum 類,所以無法再繼承,但是可以實現接口
 */
public enum WeekEnum {
    //枚舉值寫在最前面,有其他內容時,必須以分號結尾。
    //因爲枚舉只能通過常量獲取枚舉實例,所以枚舉參數必須與構造器中的參數對應
    Monday(1, "星期一") {
        @Override
        public String toSplitString() {
            return Monday.code + "," + Monday.name;
        }
    },//匹配兩個參數的構造器創建實例
    Tuesday(2, "星期二") {
        @Override
        public String toSplitString() {
            return Tuesday.getCode() + "," + Tuesday.getName();
        }
    };

    //屬性名稱可以隨便取,但是構造器中的參數類型必須與上面的枚舉參數類型對應
    private Integer code;
    private String name;

    //構造器默認是 private ,外部無法 new 枚舉對象,只能通過上面的常量獲取實例,必須與枚舉參數對應
    WeekEnum(Integer code, String name) {
        this.code = code;
        this.name = name;
    }

    public Integer getCode() {
        return code;
    }

    public String getName() {
        return name;
    }

    //方法要是 public 修飾外部才能調用
    public abstract String toSplitString();
}

2、測試代碼:

import wmx.com.springboothello.enum_wmx.WeekEnum;
public class Test {
    public static void main(String[] args) {
        //枚舉名.值 獲取實例,這些值之所以叫枚舉常量,因爲它的值就如同常量一樣一開始就頂死了的,無法修改
        WeekEnum mondayEnum = WeekEnum.Monday;
        WeekEnum tuesdayEnum = WeekEnum.Tuesday;
        System.out.println(mondayEnum.getCode() + " - " + mondayEnum.getName());//輸出:1 - 星期一
        System.out.println(tuesdayEnum.getCode() + " - " + tuesdayEnum.getName());//輸出:2 - 星期二
        System.out.println(mondayEnum.toSplitString());//輸出:1,星期一
        System.out.println(tuesdayEnum.toSplitString());//輸出:2,星期二
    }
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章