Java核心 --- 枚舉
枚舉把顯示的變量與邏輯的數字綁定在一起在編譯的時候,就會發現數據不合法也起到了使程序更加易讀,規范代碼的作用
一、用普通類的方式實現枚舉
新建一個終態類Season,把構造方法設為私有,因為枚舉值不能隨意增加因為不能new出這個類的對象,所以需要定義成員變量,把new寫在類的內部這樣,就可以在類的外部通過訪問類的靜態成員變量的方式訪問到枚舉值通過這樣的方式,只能在類的外部使用在枚舉類的內部定義的枚舉值
類Season里面是可以有方法的,我們設置地球又公轉了四分之一方法的返回值是Season,對應的這個類里面的所有枚舉值將轉動四分之一重寫方法toString(),打印枚舉的值測試一下,打印一個枚舉值的next后的值,再經過toString后輸出
/Enumeration/src/yuki/core/enumeration/imitation/SeasonTest.java
package yuki.core.enumeration.imitation;public class SeasonTest {    public static void main(String[] args) {        Season season = Season.AUTUMN;        System.out.PRintln(season.nextQuarter());    }}/Enumeration/src/yuki/core/enumeration/imitation/Season.java
package yuki.core.enumeration.test;public final class Season {    //私有構造方法    private Season(){}        //定義靜態成員常量    public final static Season SPRING = new Season();    public final static Season SUMMER = new Season();    public final static Season AUTUMN = new Season();    public final static Season WINTER = new Season();    //定義地球又公轉了四分之一    public Season nextQuarter(){        Season ret = null;        if(this == WINTER)            ret = SPRING;        else if(this == SPRING)            ret = SUMMER;        else if(this == SUMMER)            ret = AUTUMN;        else if(this == AUTUMN)            ret = WINTER;        return ret;    }        //打印枚舉的值    @Override    public String toString(){        return this == WINTER ? "Winter" : (               this == SPRING ? "Spring" : (               this == SUMMER ? "Summer" : "Autumn"));    }    }可以看到程序中出現了大量的if-else,這樣似乎不太好可以把每一個元素的nextQuarter寫成自己獨立的方法這需要定義成抽象的nextQuarter來使要新建對象就必須先實現這個方法擁有抽象方法的類也必須是抽象的這時,直接使用new來新建對象的方式就會報紅,使用它的子類創建實例對象定義為抽象的類需要子類來實現它的抽象方法,這是需要去掉final修飾符在每個枚舉值得類中實現抽象方法nextQuarter(),再次測試在這里,把統一的if-else語句轉化為了一個個獨立的類
/Enumeration/src/yuki/core/enumeration/imitation/Season.java
package yuki.core.enumeration.imitation;public abstract class Season {    //私有構造方法    private Season(){}        //定義靜態成員常量    public final static Season SPRING = new Season(){        @Override        public Season nextQuarter() {            return SUMMER;        }    };    public final static Season SUMMER = new Season(){        @Override        public Season nextQuarter() {            return AUTUMN;        }    };    public final static Season AUTUMN = new Season(){        @Override        public Season nextQuarter() {            return WINTER;        }    };    public final static Season WINTER = new Season(){        @Override        public Season nextQuarter() {            return SPRING;        }    };    public abstract Season nextQuarter();        //打印枚舉的值    @Override    public String toString(){        return this == WINTER ? "Winter" : (               this == SPRING ? "Spring" : (               this == SUMMER ? "Summer" : "Autumn"));    }    }運行結果如下:
Winter
二、一個基本的枚舉類這里把枚舉放在類里定義,作為測試類的一個成員內部類枚舉里的一個元素就相當于類里的一個對象對于枚舉這種類型的對象,它自動的幫我們實現了toString方法打印出的是枚舉值的接收引用的名稱
方法name()獲得接收引用的名稱方法ordinal()獲得枚舉值在枚舉中所在的位置,下表從0開始靜態方法valueOf(String)可以通過枚舉值的名稱得到枚舉值從瀏覽器獲得的請求參數值就可以通過這種方式編程枚舉值對象靜態方法values()可以獲得枚舉里的所有枚舉值
/Enumeration/src/yuki/core/enumeration/construction/SquareVertexTest.java
package yuki.core.enumeration.construction;public class SquareVertexTest {    public static void main(String[] args) {        SquareVertex vertex = SquareVertex.A;        System.out.println(vertex);        System.out.println(vertex.name());        System.out.println(vertex.ordinal());        System.out.println(SquareVertex.valueOf("D"));        System.out.println(SquareVertex.values().length);    }        /**     * 正方形的四個頂點     */    public enum SquareVertex{        A, B, C, D    }}運行結果如下:
AA0D4
三、帶有構造方法的枚舉枚舉是一個類,所以應該可以定義自己的構造方法構造方法必須放在元素列表之后,并在元素列表之后加上分號構造方法必須是私有的,默認調用的是無參構造所有的枚舉值在第一次用到枚舉類時全部初始化
在枚舉元素后加圓括號指定參數列表,可以調用對應的構造方法在枚舉元素后加上沒有內容的圓括號,調用的方法也是無參構造方法
/Enumeration/src/yuki/core/enumeration/construction/DirectionTest.java
package yuki.core.enumeration.construction;public class DirectionTest {    public static void main(String[] args) {        @SuppressWarnings("unused")        Direction direction = Direction.W;    }        public enum Direction{        E(1), S(), W, N;        private Direction(){            System.out.println("無參構造方法");        }        private Direction(int direct){            System.out.println("Direction(int direct)");        }            }}運行結果如下:
Direction(int direct)無參構造方法無參構造方法無參構造方法
四、實現帶有抽象方法的枚舉添加一個抽象方法返回類型是枚舉類本身在枚舉元素后添加花括號實現這個抽象方法
/Enumeration/src/yuki/core/enumeration/abstraction/ColorTest.java
package yuki.core.enumeration.abstraction;public class ColorTest {    public static void main(String[] args) {            }        public enum TrafficLamp{        RED{            @Override            public TrafficLamp nextLamp() {                return GREEN;            }        },         GREEN{            @Override            public TrafficLamp nextLamp() {                return YELLOW;            }        },         YELLOW{            @Override            public TrafficLamp nextLamp() {                return RED;            }        };        public abstract TrafficLamp nextLamp();    }}在bin目錄下可以看到枚舉的每個元素都生成了class文件D:/Workspaces/Eclipse/Enumeration/bin/yuki/core/enumeration/abstraction

為燈指定一個時間,這時需要在枚舉元素的后面加上構造參數
/Enumeration/src/yuki/core/enumeration/abstraction/LampTest.java
package yuki.core.enumeration.abstraction;public class LampTest {    public static void main(String[] args) {            }        public enum TrafficLamp{        RED(30){            @Override            public TrafficLamp nextLamp() {                return GREEN;            }        },         GREEN(45){            @Override            public TrafficLamp nextLamp() {                return YELLOW;            }        },         YELLOW(5){            @Override            public TrafficLamp nextLamp() {                return RED;            }        };        public abstract TrafficLamp nextLamp();        @SuppressWarnings("unused")        private int time;        private TrafficLamp(int time){            this.time = time;        }    }}在新建父類的匿名子類對象時,可以指定調用父類的構造方法
/Enumeration/src/yuki/core/enumeration/abstraction/ConstructorTest.java
package yuki.core.enumeration.abstraction;public class ConstructorTest {    public static void main(String[] args) {                Supper supper = new Supper(1234){            @Override public String toString(){                return "子類的toString方法";            }        };        System.out.println(supper);    }    public static class Supper{        public Supper() {            System.out.println("無參構造被調用");        }        public Supper(int i){            System.out.println("有參構造被調用");        }    }}運行結果如下:
有參構造被調用子類的toString方法
如果枚舉只有一個成員,可以作為一種單例模式的實現方式更多內容請參考:[張孝祥Java高新技術_枚舉]
五、為枚舉提供的功能和演示1. 枚舉與switch-caseswitch中匹配枚舉值時,只需要寫出不帶枚舉類型的枚舉值就可以了
/Enumeration/src/yuki/core/enumeration/switch_case/QuarkTest.java
package yuki.core.enumeration.switch_case;public class QuarkTest {    public static void main(String[] args) {        Quark quark = Quark.C;        String name = null;        switch(quark){        case U:             name = "上夸克";            break;        case D:             name = "下夸克";            break;        case C:             name = "粲夸克";            break;        case S:             name = "奇夸克";            break;        case T:             name = "頂夸克";            break;        case B:             name = "底夸克";            break;        }        System.out.println(name);    }    private enum Quark{        U, D, C, S, T, B;    }}運行結果如下:
粲夸克
2. 定制自己的枚舉字符串這樣就可以不用public static final String variable_name = string_value;
/Enumeration/src/yuki/core/enumeration/const_string/WebsiteTest.java
package yuki.core.enumeration.const_string;public class WebsiteTest {    private enum Website{        GOOGLE("https://www.google.com.hk/?gws_rd=ssl"),        AMAZON("http://www.amazon.cn/");                //網址        private String address;        //構造函數        private Website(String address){            this.address = address;        }        //獲取地址的方法        public String address() {            return address;        }    }        public static void main(String[] args) {                Website amazon = Website.AMAZON;        System.out.println(amazon);        System.out.println(amazon.address());    }}運行結果如下:
AMAZONhttp://www.amazon.cn/
3. EnumSet和EnumMap
JDK5.0 中在增加 Enum 類的同時,也增加了兩個工具類 EnumSet 和 EnumMap,這兩個類都放在 java.util 包中。
/Enumeration/src/yuki/core/enumeration/enum_util/EnumSetTest.java
package yuki.core.enumeration.enum_util;import java.util.EnumSet;/** * JDK5.0 中在增加 Enum 類的同時,也增加了兩個工具類 EnumSet 和 EnumMap,  * 這兩個類都放在 java.util 包中。 *  * EnumSet 是一個針對枚舉類型的高性能的 Set 接口實現。  * EnumSet 中裝入的所有枚舉對象都必須是同一種類型,  * 在其內部,是通過bit-vector 來實現,也就是通過一個 long 型數。  * EnumSet 支持在枚舉類型的所有值的某個范圍中進行迭代。 *  * @author yuki *  */public class EnumSetTest {    private enum WeekDay{        Mon, Tue, Wed, Thu, Fri, Sat, Sun;    }        public static void main(String[] args) {//        EnumSet<WeekDay> weekDays = EnumSet.of(WeekDay.Fri, WeekDay.Tue);        EnumSet<WeekDay> weekDays = EnumSet.range(WeekDay.Tue, WeekDay.Fri);        for(WeekDay day : weekDays){            System.out.println(day);        }    }    }運行結果如下:
TueWedThuFri
/Enumeration/src/yuki/core/enumeration/enum_util/EnumMapTest.java
package yuki.core.enumeration.enum_util;import java.util.EnumMap;import java.util.Map;/** * 與EnumSet 類似,EnumMap 也是一個高性能的 Map 接口實現,  * 用來管理使用枚舉類型作為 keys 的映射表,內部是通過數組方式來實現。 * EnumMap 將豐富的和安全的 Map 接口與數組快速訪問結合到一起,  * 如果你希望要將一個枚舉類型映射到一個值,你應該使用 EnumMap。 *  * @author yuki *  */public class EnumMapTest {    //卦值    private enum Divination{        KAN, XUN, QIAN, DUI, LI, ZHENG, KUN, GEN    }    //自然值    private enum Nature{        SHUI, FENG, TIAN, ZE, HUO, LEI, DI, SHAN    }    public static void main(String[] args) {        //將卦值與自然值對應起來        Map<Divination, Nature> schema = new EnumMap<>(Divination.class);        for(int i = 0; i < Divination.values().length; ++i){            schema.put(Divination.values()[i], Nature.values()[i]);        }        for(Map.Entry<Divination, Nature> entry : schema.entrySet()){            System.out.println(entry.getKey() + "/t->/t" + entry.getValue());        }    }}運行結果如下:
KAN -> SHUIXUN -> FENGQIAN -> TIANDUI -> ZELI -> HUOZHENG -> LEIKUN -> DIGEN -> SHAN
更多疑問請參考:[Java 語言中 Enum 類型的使用介紹]:http://www.ibm.com/developerworks/cn/java/j-lo-enum/index.html
六、反編譯工具jdecompiler下載地址:http://jd.benow.ca/ ,點擊下載JD-Eclipse>Offline installation
 按照提示的步驟安裝,把下載文件解壓到以壓縮包名為文件名的文件夾Help>InstallNewSoftware...>Add>AddRepository>選擇文件夾jdeclipse_update_siteName=jdeclipse; Location=C:/Users/yuki/Downloads/jdeclipse_update_site點擊OK,列表中出現Java Decompiler Eclipse Plug-in>勾選它>Next這時鼠標的指針變為等待,顯示Calculating requirements and dependencies額,這好像要等好久,我去吃飯了,~~,哦,只是前面慢而已,點擊Next選擇I accept the terms of the license agreement>Finish顯示InstallSoftware的彈出窗,這里又好慢再按照提示添加EmmanuelDupuy>選中>Finish>安裝完成>restart Eclipse
按照提示的步驟安裝,把下載文件解壓到以壓縮包名為文件名的文件夾Help>InstallNewSoftware...>Add>AddRepository>選擇文件夾jdeclipse_update_siteName=jdeclipse; Location=C:/Users/yuki/Downloads/jdeclipse_update_site點擊OK,列表中出現Java Decompiler Eclipse Plug-in>勾選它>Next這時鼠標的指針變為等待,顯示Calculating requirements and dependencies額,這好像要等好久,我去吃飯了,~~,哦,只是前面慢而已,點擊Next選擇I accept the terms of the license agreement>Finish顯示InstallSoftware的彈出窗,這里又好慢再按照提示添加EmmanuelDupuy>選中>Finish>安裝完成>restart Eclipse
打開Perferences>Java>Decompile,表明已經安裝成功,當然下載的svn也是上面格式的文件,所以應該也可以用上面的方式安裝General>Editor>FileAssociation>點擊*.class without source看到默認是用ClassFileEditor打開的,從它的圖標不難看出,它就是把class文件反編譯為java文件格式打開的編輯器

在很多情況下我們是有源碼的,當源碼在maven庫中對應的位置時maven工具就會自動下載源碼,并用ClassFileViewer打開在設為默認后,重新打開Eclipse會發現默認的class打開方式還是反編譯打開點擊General>StartupAndShutdown,這里有一個檢查項JD-Eclipse Plug-in取消它的勾選就可以了

七、反編譯枚舉類的類文件bin目錄下的內容按照Eclipse的設定是不顯示的在src下的class文件也是默認不顯示的寫一個枚舉類PlatonicSolid,里面有五種元素
package yuki.core.enumeration.decompiler;public enum PlatonicSolid {    FOUR, EIGHT, TWENTY, SIX, TWELVE}打開/Enumeration/bin/yuki/core/enumeration/decompiler/復制PlatonicSolid.class到根目錄下打開后,文件以為自己是有源碼的,所以這里反編譯不起作用

訪問http://jd.benow.ca/ 下載JD-GUI,證明這個反編譯器打不開編譯后的枚舉類文件額,不是要下載右邊那個,左邊那個是穩定版
 打開后反編譯的結果就僅僅是源碼去掉了注釋看起來軟件升級了,看不到想要看的內容了
打開后反編譯的結果就僅僅是源碼去掉了注釋看起來軟件升級了,看不到想要看的內容了

反編譯網站:http://www.findmaven.net/decompile ,同樣的結果反編譯網站:http://www.showmycode.com/ 反編譯結果如下

經過我的排板后的文件如下:因為編譯不通過,所以用Ctrl+Shift+F排版是不行的
/Enumeration/src/yuki/core/enumeration/decompiler/platonic_solid/PlatonicSolid.java
package yuki.core.enumeration.decompiler.platonic_solid;public final class PlatonicSolid extends Enum<Enum<E>> {       private PlatonicSolid(String s, int i) {         super(s, i);    }       public static PlatonicSolid[] values() {         PlatonicSolid aplatonicsolid[];         int i;         PlatonicSolid aplatonicsolid1[];         System.arraycopy(aplatonicsolid = enum$VALUES, 0,         aplatonicsolid1 = new PlatonicSolid[i = aplatonicsolid.length], 0, i);         return aplatonicsolid1;     }       public static PlatonicSolid valueOf(String s) {         return (PlatonicSolid)enum.valueOf(yuki/core/enumeration/decompiler/PlatonicSolid, s);     }       public static final PlatonicSolid FOUR;     public static final PlatonicSolid EIGHT;     public static final PlatonicSolid TWENTY;     public static final PlatonicSolid SIX;     public static final PlatonicSolid TWELVE;     private static final PlatonicSolid enum$VALUES[];        static {         FOUR = new PlatonicSolid("FOUR", 0);         EIGHT = new PlatonicSolid("EIGHT", 1);         TWENTY = new PlatonicSolid("TWENTY", 2);         SIX = new PlatonicSolid("SIX", 3);         TWELVE = new PlatonicSolid("TWELVE", 4);         enum$VALUES = (new PlatonicSolid[] { FOUR, EIGHT, TWENTY, SIX, TWELVE });     }}但是Enum是無法被繼承的,具體請見:http://www.zhihu.com/question/19908744http://pf-miles.VEvb.com/blog/187155后一篇文章所說的內容就是,枚舉的多態是由屬性的類繼承枚舉類實現的
枚舉類的聲明如下:
public abstract class Enum<E extends Enum<E>>implements Comparable<E>, Serializable
這里的E繼承了Enum<E>, 而枚舉E又是枚舉類的泛型參數,如果可以繼承public final class PlatonicSolid extends Enum<Enum<E>>那么就必須要擁有一個繼承了枚舉的枚舉類,這又回到了剛才的問題,所以問題無解
八、構造方法,方法,變量枚舉類型的每一個值都將映射到protected Enum(String name, int ordinal)構造函數中在這里,每個值的名稱都被轉換成一個字符串,并且序數設置表示了每個設置的優先值。換句話說,enum Size {Small, Medium, Large}將映射到清單 2 中所示的構造函數調用中:new Enum<Size>("Small", 0);new Enum<Size>("Medium", 1);new Enum<Size>("Large", 2);
更多疑問請參考:[馴服 Tiger: 深入研究枚舉類型]:http://www.ibm.com/developerworks/cn/java/j-tiger04195/
九、實現接口與使用接口組織枚舉所有的枚舉都繼承自java.lang.Enum類。由于Java 不支持多繼承,所以枚舉對象不能再繼承其他類。
/Enumeration/src/yuki/core/enumeration/interfaces/PlanetTest.java
package yuki.core.enumeration.interfaces;import java.util.Arrays;import java.util.List;public class PlanetTest {        private interface Move{        void move();    };        private enum Planet implements Move{        SOLAR,         EARTH{            @Override            public void move() {                System.out.println("rounding...center:" + SOLAR);            }        },         MOON{            @Override            public void move() {                System.out.println("rounding...center:" + EARTH);            }        };                @Override        public void move() {            System.out.println("rounding...");        }    }    public static void main(String[] args) {                List<Planet> planets = Arrays.asList(Planet.values());        for(Planet planet : planets){            System.out.print(planet + " : ");            planet.move();        }    }}運行結果如下:
SOLAR : rounding...EARTH : rounding...center:SOLARMOON : rounding...center:EARTH
使用接口也可以管理枚舉,并且可以在接口內部再定義接口
/Enumeration/src/yuki/core/enumeration/interfaces/Shape.java
package yuki.core.enumeration.interfaces;public interface Shape {    enum Circle implements Shape {        Center, Radius    }        interface RegularPolygon extends Shape {        enum Triangle implements RegularPolygon {            Angel, Length        }        enum Square implements RegularPolygon {            Point, Area        }    }}/Enumeration/src/yuki/core/enumeration/interfaces/ShapeTest.java
package yuki.core.enumeration.interfaces;public class ShapeTest {    public static void main(String[] args) {                Shape circle = Shape.Circle.Radius;        System.out.println(circle);                Shape squre = Shape.RegularPolygon.Square.Area;        System.out.println(squre);    }}運行結果如下:
RadiusArea
更多疑問請參考:[Java 枚舉7常見種用法]:http://softbeta.VEvb.com/blog/1185573http://m.survivalescaperooms.com/happyPawpaw/archive/2013/04/09/3009553.html
更多好文請查看:http://m.survivalescaperooms.com/kodoyang/
點擊下方的紅色按鈕“ 關注我 ”吧!
孔東陽
2014/10/2
新聞熱點
疑難解答