Java列舉型別的使用和原理

Qhearts發表於2017-04-26

列舉的特點

◆型別安全(Type Safety)
◆緊湊有效的列舉數值定義(Compact, Efficient Declaration of Enumerated Values)
◆無縫的和程式其它部分的互動操作(Seamless integration with other language features)
◆執行的高效率(Runtime efficiency

列舉型別概念

public class EnumDemoOne {  
    private enum InnerEnum {  
        RED, GREEN, YELLOW  
    };  

    public static void main(String[] args) {  
        System.out.println(InnerEnum.RED);  
        System.out.println(InnerEnum.GREEN);  
        System.out.println(InnerEnum.YELLOW);  
    }  
}

執行上面的程式碼,將編輯產生EnumDemoOne.class和EnumDemoOne$InnerEnum.class。
由此說明定義列舉型別其實就是在定義一個類,只不過很多細節由編譯器幫你補齊了,所以,某種程度上enum關鍵詞的作用就像是class或interface.當使用enum定義列舉型別時,實際上所定義出來的型別是繼承自Java.lang.Enum類。

PS:我常把InnerEnum叫做列舉型別,把其中的RED等叫做列舉變數或列舉值。


public enum Color {  
    RED{  
        public String getName(){  
            return "紅色";  
        }  
    }  
    ,GREEN{  
        public String getName(){  
            return "綠色";  
        }  
    }  
    ,YELLOW{  
        public String getName(){  
            return "黃色";  
        }  
    };  
    public abstract String getName();  
}

如果RED只是一個Color類的一個static final的例項,那麼上面的程式碼就很讓了費解了,為什麼在列舉型別中可以有一個抽象方法,而每個列舉值可以對其重新實現?
別急,看了我對這個類的測試程式碼你就明白,測試程式碼如下:

public class EnumDemoFour{  
    public static void main(String[] args){  
        //列印該列舉值的名稱  
        System.out.println(Color.RED.getName());  
        //列印該列舉值的類  
        System.out.println(Color.RED.getClass());  
        //列印該列舉值的類的父類  
        System.out.println(Color.RED.getClass().getSuperclass());  
        //列印該列舉值的類的父類的父類
        System.out.println(Color.RED.getClass().getSuperclass().getSuperclass());  
        //列印該列舉型別的修飾符  
        System.out.println(Modifier.toString(Color.class.getModifiers()));  
    }     
    /*執行結果 
    紅色 
    class com.lxq.enumm.Color$1 
    class com.lxq.enumm.Color 
    class java.lang.Enum 
    public abstract*/  
} 
該執行結果首先說明了RED和Color不是同一個類,而是前者是後者的一個子類;同時也說明了enum申明的其實是一個abstract的類,所以Color中可以有抽象方法。
那麼,我們應該這麼理解列舉型別的原理,首先enum Color繼承了Java.lang.Enum這個抽象類,但enum Color還是一個抽象類,所以它可以有抽象方法和非抽象方法。

而enum Color中的列舉值變數RED事實上上Color的一個匿名子類,所以它可以實現Color中的抽象方法,這樣,當我們呼叫System.out.println(Color.RED.getName());
就是呼叫了匿名子類實現的方法。當然這些過程的很多事都有編譯器等為我們做了,所以這裡的程式碼很簡單。
要是你不明白上面列印的內容,我再提供一個普通的類給你看看,還是類似的效果哦。

public abstract class TestInnerClass {  
    public abstract void dosomething();  
    public static void main(String[] args){  
        TestInnerClass tic=new TestInnerClass(){  
            @Override  
            public void dosomething() {  
                System.out.println("我是匿名子類");  
            }     
        };  
        tic.dosomething();  
        System.out.println(tic.getClass());  
    }  
    /*輸出結果 
    我是匿名子類 
    class TestInnerClass$1 
    */  
}  

最後再附上網上一個使用Java普通類模擬列舉的例子http://blog.csdn.net/xyang81/article/details/7185428,這個例子真的很好。
使用Java普通類模擬列舉

import java.util.HashMap;  
import java.util.Map;  

/** 
 * 模擬星期中的表示的天,每個星期天都表示一個物件 
 * 1、類中的每一個列舉成員都是該類的一個例項物件 
 * 2、建構函式私有化 
 * 3、提供操作列舉成員的抽象方法和靜態方法 
 */  
public abstract class WeekDate {  
    /** 
     * 星期一 
     */  
    public static final WeekDate MON = new WeekDate("MON",0) {//匿名子類  
        @Override  
        public WeekDate nextDay() {  
            return TUES;  
        }  
        @Override  
        public WeekDate preDay() {  
            return SUN;  
        }  
        @Override  
        public String toString() {  
            return "WeekDate.MON";  
        }  
    };    

    /** 
     * 星期二 
     */  
    public static final WeekDate TUES = new WeekDate("TUES",1) {  
        @Override  
        public WeekDate nextDay() {  
            return WEDNES;  
        }  
        @Override  
        public WeekDate preDay() {  
            return MON;  
        }  
        @Override  
        public String toString() {  
            return "WeekDate.TUES";  
        }  
    };  

    /** 
     * 星期三 
     */  
    public static final WeekDate WEDNES = new WeekDate("WEDNES",2) {  
        @Override  
        public WeekDate nextDay() {  
            return THURS;  
        }  
        @Override  
        public WeekDate preDay() {  
            return TUES;  
        }  
        @Override  
        public String toString() {  
            return "WeekDate.WEDNES";  
        }     
    };  

    /** 
     * 星期四 
     */  
    public static final WeekDate THURS = new WeekDate("THURS",3) {  
        @Override  
        public WeekDate nextDay() {  
            return FRI;  
        }  
        @Override  
        public WeekDate preDay() {  
            return WEDNES;  
        }         
        @Override  
        public String toString() {  
            return "WeekDate.THURS";  
        }         
    };  

    /** 
     * 星期五 
     */  
    public static final WeekDate FRI = new WeekDate("FRI",4){  
        @Override  
        public WeekDate nextDay() {  
            return SATUR;  
        }  
        @Override  
        public WeekDate preDay() {  
            return THURS;  
        }  
        @Override  
        public String toString() {  
            return "WeekDate.FRI";  
        }  
    };  

    /** 
     * 星期六 
     */  
    public static final WeekDate SATUR = new WeekDate("SATUR",5){  
        @Override  
        public WeekDate nextDay() {  
            return SUN;  
        }  
        @Override  
        public WeekDate preDay() {  
            return FRI;  
        }         
        @Override  
        public String toString() {  
            return "WeekDate.SATUR";  
        }         
    };  

    /** 
     * 星期日 
     */  
    public static final WeekDate SUN = new WeekDate("SUN",6){  
        @Override  
        public WeekDate nextDay() {  
            return MON;  
        }  
        @Override  
        public WeekDate preDay() {  
            return SATUR;  
        }  
        @Override  
        public String toString() {  
            return "WeekDate.SUN";  
        }  
    };  

    private static Map<String, WeekDate> valueMap = new HashMap<String, WeekDate>();  

    /** 
     * 列舉名稱 
     */  
    private final String name;  

    /** 
     * 列舉成員的順序 
     */  
    private final int ordinal;  

    private WeekDate(String name,int ordinal) {  
        this.name = name;  
        this.ordinal = ordinal;  
    }  

    /** 
     * 儲存列舉成員 
     */  
    private static WeekDate[] values = {  
        MON,TUES,WEDNES,THURS,FRI,SATUR,SUN  
    };  

    //初始化  
    static {  
        valueMap.put("MON", values[0]);  
        valueMap.put("TUES", values[1]);  
        valueMap.put("WEDNES", values[2]);  
        valueMap.put("THURS", values[3]);  
        valueMap.put("FRI", values[4]);  
        valueMap.put("SATUR", values[5]);  
        valueMap.put("SUN", values[6]);  
    }  

    /** 
     * 下一天 
     * @return 
     */  
    public abstract WeekDate nextDay();  

    /** 
     * 前一天 
     * @return 
     */  
    public abstract WeekDate preDay();  

    /** 
     * 列舉中的所有成員 
     * @return 
     */  
    public static WeekDate[] values() {  
        return values;  
    }  

    /** 
     * 將一個字串轉換成一個列舉成員物件 
     * @param name 列舉名稱 
     * @return 列舉物件 
     */  
    public static WeekDate valueOf(String name) {  
        if (name.equalsIgnoreCase("MON")) {  
            return MON;  
        } else if (name.equalsIgnoreCase("TUES")) {  
            return TUES;  
        } else if (name.equalsIgnoreCase("WEDES")) {  
            return WEDNES;  
        } else if (name.equalsIgnoreCase("THURS")) {  
            return THURS;  
        } else if (name.equalsIgnoreCase("FRI")) {  
            return FRI;  
        } else if (name.equalsIgnoreCase("SATUR")) {  
            return SATUR;  
        } else if (name.equalsIgnoreCase("SUN")) {  
            return SUN;  
        } else {  
            throw new IllegalArgumentException("找不到" + name + "列舉型別!");  
        }  
    }  

    /** 
     * 優化字串轉列舉物件 
     * @param name 列舉名稱 
     * @return 列舉物件 
     */  
    public static WeekDate valueOf_2(String name) {  
        WeekDate value = valueMap.get(name.toUpperCase());  
        if (value == null) {  
            throw new IllegalArgumentException("找不到" + name + "列舉型別!");  
        }  
        return value;  
    }  
    public String getName() {  
        return name;  
    }  
    public int getOrdinal() {  
        return ordinal;  
    }  
}

使用JDK5.0中提供的列舉特性

/** 
 * 列舉的應用 
 * 儲存每週中的天份 
 */  
public enum WeekDateEnum {  

    MON {  

        @Override  
        public WeekDateEnum nextDay() {  
            return TUES;  
        }  

        @Override  
        public WeekDateEnum preDay() {  
            return SUN;  
        }  

    },  TUES {  

        @Override  
        public WeekDateEnum nextDay() {  
            return WEDNES;  
        }  

        @Override  
        public WeekDateEnum preDay() {  
            return MON;  
        }  

    },  WEDNES {  

        @Override  
        public WeekDateEnum nextDay() {  
            return THURS;  
        }  

        @Override  
        public WeekDateEnum preDay() {  
            return TUES;  
        }  

    },  THURS {  

        @Override  
        public WeekDateEnum nextDay() {  
            return FRI;  
        }  

        @Override  
        public WeekDateEnum preDay() {  
            return WEDNES;  
        }  

    },  FRI {  

        @Override  
        public WeekDateEnum nextDay() {  
            return SATUR;  
        }  

        @Override  
        public WeekDateEnum preDay() {  
            return THURS;  
        }  

    },  SATUR {  

        @Override  
        public WeekDateEnum nextDay() {  
            return SATUR;  
        }  

        @Override  
        public WeekDateEnum preDay() {  
            return FRI;  
        }  

    },  SUN {  

        @Override  
        public WeekDateEnum nextDay() {  
            return SATUR;  
        }  

        @Override  
        public WeekDateEnum preDay() {  
            return MON;  
        }  

    };  

    private WeekDateEnum() {}  

    /** 
     * 下一天 
     * @return 
     */  
    public abstract WeekDateEnum nextDay();  

    /** 
     * 前一天 
     * @return 
     */  
    public abstract WeekDateEnum preDay();  

    /** 
     * 列舉物件公共的toString方法,可以在case塊中反饋自己想要返回的資訊 
     */  
    public String toString() {  
        switch (this) {  
        case MON:  
            return "WeekDateEnum.MON";  
        case TUES:  
            return "WeekDateEnum.TUES";  
        case WEDNES:  
            return "WeekDateEnum.WEDNES";  
        case THURS:  
            return "WeekDateEnum.THURS";  
        case FRI:  
            return "WeekDateEnum.FRI";  
        case SATUR:  
            return "WeekDateEnum.SATUR";  
        case SUN:  
            return "WeekDateEnum.SUN";  
        default:  
            return null;  
        }  
    }  
}  

列舉功能測試

/** 
 * 列舉功能測試 
 */  
public class EnumTest {  

    public static void main(String[] args) {  

        //使用普通JAVA類模擬列舉的應用  
        WeekDate weekDate = WeekDate.MON;       //獲得一個列舉物件  
        //呼叫列舉中提供的方法  
        System.out.println(weekDate.nextDay());   
        System.out.println(weekDate.preDay());  
        System.out.println(weekDate.getName());  
        //獲得列舉成員所在列舉成員列表中的位置  
        System.out.println(weekDate.getOrdinal());  
        //呼叫某一個列舉成員的方法  
        System.out.println(WeekDate.values()[0].preDay());  
        System.out.println("---------------遍歷列舉成員,普通JAVA類模擬--------------------------");  
        for (WeekDate weekDate2 : WeekDate.values()) {  
            System.out.println(weekDate2);  
        }  

        System.out.println("\n=================================================================\n");  

        //使用JDK中提供的列舉特性功能應用  
        WeekDateEnum weekDateEnum = WeekDateEnum.MON;   //獲得一個列舉物件  
        System.out.println(WeekDate.values().length);   //獲得列舉成員數量  
        System.out.println(weekDateEnum.name());        //獲得列舉的字串名稱  
        System.out.println(weekDateEnum.toString());    //列印列舉物件,已重寫toString方法,預設列印列舉的名稱  
        System.out.println(weekDateEnum.nextDay().ordinal());   //列舉成員列表中的位置  
        System.out.println(WeekDateEnum.valueOf("FRI").nextDay().ordinal());  
        System.out.println("---------------遍歷列舉成員,使用JDK的列舉特性-------------------------");  
        for (WeekDateEnum enumDemo : WeekDateEnum.values()) {  
            System.out.println(enumDemo);  
        }  

    }   

} 

轉載於:http://blog.csdn.net/sup_heaven/article/details/35559117

相關文章