1. 程式人生 > >Enum列舉詳解和EnumSet、EnumMap使用

Enum列舉詳解和EnumSet、EnumMap使用

一、Enum列舉

public enum Day {
    MONDAY,TUESDAY,WEDNESDAY,THURSDAY,FRIDAY,SATURDAY,SUNDAY;
}

一個簡單的測試類:

public class TestEnum {

    public static void main(String[] args) {
        Day today=Day.FRIDAY;
        switch(today)
        {
        case MONDAY:
            System.out.println("today is monday"
); break; case TUESDAY: System.out.println("today is tuesday"); break; case WEDNESDAY: System.out.println("today is webnesday"); break; case THURSDAY: System.out.println("today is thursday"); break
; case FRIDAY: System.out.println("today is firday"); break; case SATURDAY: System.out.println("today is saturday"); break; case SUNDAY: System.out.println("today is sunday"); break; } } }

測試結果:

today is firday

Day列舉的本質就是一個類,編譯器會自動為我們生成Day類,通過反編譯得到該類如下:

final class Day extends Enum
{
    //編譯器為我們新增的靜態的values()方法
    public static Day[] values()
    {
        return (Day[])$VALUES.clone();
    }
    //編譯器為我們新增的靜態的valueOf()方法,注意間接呼叫了Enum也類的valueOf方法
    public static Day valueOf(String s)
    {
        return (Day)Enum.valueOf(com/zejian/enumdemo/Day, s);
    }
    //私有建構函式
    private Day(String s, int i)
    {
        super(s, i);
    }
     //前面定義的7種列舉例項
    public static final Day MONDAY;
    public static final Day TUESDAY;
    public static final Day WEDNESDAY;
    public static final Day THURSDAY;
    public static final Day FRIDAY;
    public static final Day SATURDAY;
    public static final Day SUNDAY;
    private static final Day $VALUES[];

    static 
    {    
        //例項化列舉例項
        MONDAY = new Day("MONDAY", 0);
        TUESDAY = new Day("TUESDAY", 1);
        WEDNESDAY = new Day("WEDNESDAY", 2);
        THURSDAY = new Day("THURSDAY", 3);
        FRIDAY = new Day("FRIDAY", 4);
        SATURDAY = new Day("SATURDAY", 5);
        SUNDAY = new Day("SUNDAY", 6);
        $VALUES = (new Day[] {
            MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY
        });
    }
}

可以清楚地看出每個列舉型別即星期數就是該Day類的一個例項物件,該構成方式和單例模式有些類似,故可以用只有一個列舉型別的列舉作為單例模式,而且列舉的構造器由編譯器管理安全性十分高,既可以防止反射破解也可以防止反序列破解。

Day類繼承了Enum類,下面看下Enum程式碼,可以更好理解列舉的方法:

public abstract class Enum<E extends Enum<E>>
        implements Comparable<E>, Serializable {

    private final String name; //列舉字串名稱

    public final String name() {
        return name;
    }

    private final int ordinal;//列舉順序值

    public final int ordinal() {
        return ordinal;
    }

    //列舉的構造方法,只能由編譯器呼叫
    protected Enum(String name, int ordinal) {
        this.name = name;
        this.ordinal = ordinal;
    }

    public String toString() {
        return name;
    }

    public final boolean equals(Object other) {
        return this==other;
    }

    //比較的是ordinal值
    public final int compareTo(E o) {
        Enum<?> other = (Enum<?>)o;
        Enum<E> self = this;
        if (self.getClass() != other.getClass() && // optimization
            self.getDeclaringClass() != other.getDeclaringClass())
            throw new ClassCastException();
        return self.ordinal - other.ordinal;//根據ordinal值比較大小
    }

    @SuppressWarnings("unchecked")
    public final Class<E> getDeclaringClass() {
        //獲取class物件引用,getClass()是Object的方法
        Class<?> clazz = getClass();
        //獲取父類Class物件引用
        Class<?> zuper = clazz.getSuperclass();
        return (zuper == Enum.class) ? (Class<E>)clazz : (Class<E>)zuper;
    }


    public static <T extends Enum<T>> T valueOf(Class<T> enumType,
                                                String name) {
        //enumType.enumConstantDirectory()獲取到的是一個map集合,key值就是name,value則是列舉變數值   
        //enumConstantDirectory是class物件內部的方法,根據class物件獲取一個map集合的值       
        T result = enumType.enumConstantDirectory().get(name);
        if (result != null)
            return result;
        if (name == null)
            throw new NullPointerException("Name is null");
        throw new IllegalArgumentException(
            "No enum constant " + enumType.getCanonicalName() + "." + name);
    }

    //.....省略其他沒用的方法
}

二、EnumMap

public class TestEnumMap {

    public static void main(String[] args) {

        Day today=Day.FRIDAY;

        EnumMap enummap=new EnumMap(Day.class); //對應Day類的EnumMap
        enummap.put(Day.MONDAY, "work work");   //第一個值為key不能為null,第二個值為values可以為null
        enummap.put(Day.TUESDAY, "work work");  //第一個值填入列舉例項,第二個值為該列舉例項的記錄資訊
        enummap.put(Day.WEDNESDAY, "work work");
        enummap.put(Day.THURSDAY, "work work");
        enummap.put(Day.FRIDAY, "work work");
        enummap.put(Day.SATURDAY, "have fun");
        enummap.put(Day.SUNDAY, "have fun");

        System.out.println(enummap);

        String job=(String) enummap.get(today); //用get方法輸入key值獲得今天的工作資訊
        System.out.println("job is:"+job);

    }

}

輸出結果為:

{MONDAY=work work, TUESDAY=work work, WEDNESDAY=work work, THURSDAY=work work, FRIDAY=work work, SATURDAY=have fun, SUNDAY=have fun}
job is:work work

這個例子很清晰展示了EnumMap的基本用法

三、EnumSet

1.noneOf建立空佇列

public class TestEnumSet {

    public static void main(String[] args) {
        EnumSet enumset=EnumSet.noneOf(Day.class);//建立一個空的Day列舉型別的佇列
        System.out.println("Before:"+enumset);    //新增元素前狀態
        enumset.add(Day.MONDAY);                  //新增三個元素
        enumset.add(Day.TUESDAY);
        enumset.add(Day.WEDNESDAY);
        System.out.println("After:"+enumset);     //新增元素後狀態
    }

}

執行結果:

Before:[]
After:[MONDAY, TUESDAY, WEDNESDAY]

2.allOf建立滿佇列

public class TestEnumSet {

    public static void main(String[] args) {
        EnumSet enumset=EnumSet.allOf(Day.class);
        System.out.println(enumset);
    }

}

執行結果:

[MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY]

3.range建立指定範圍佇列

public class TestEnumSet {

    public static void main(String[] args) {
        EnumSet enumset=EnumSet.range(Day.MONDAY, Day.FRIDAY);
        System.out.println(enumset);
    }

}

執行結果:

[MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY]

4.complementOf補集建立佇列

public class TestEnumSet {

    public static void main(String[] args) {
        EnumSet enumset1=EnumSet.range(Day.MONDAY, Day.FRIDAY);
        System.out.println("enumset1:"+enumset1);

        EnumSet enumset2=EnumSet.complementOf(enumset1);//建立enumset1的補集enumset2
        System.out.println("enumset2:"+enumset2);
    }

}

執行結果:

enumset1:[MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY]
enumset2:[SATURDAY, SUNDAY]

5.copyOf複製建立

public class TestEnumSet {

    public static void main(String[] args) {
        EnumSet enumset1=EnumSet.range(Day.MONDAY, Day.FRIDAY);
        System.out.println("enumset1:"+enumset1);

        EnumSet enumset2=EnumSet.copyOf(enumset1);//複製enumset1建立enumset2
        System.out.println("enumset2:"+enumset2);
    }

}

執行結果:

enumset1:[MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY]
enumset2:[MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY]

6.copyOf複製ArrayList建立

public class TestEnumSet {

    public static void main(String[] args) {
        ArrayList<Day> list=new ArrayList<Day>();
        list.add(Day.MONDAY);
        list.add(Day.TUESDAY);
        list.add(Day.WEDNESDAY);
        list.add(Day.WEDNESDAY);
        System.out.println("list:"+list);

        EnumSet enumset=EnumSet.copyOf(list);
        System.out.println("enumset:"+enumset);
    }

}

執行結果:

list:[MONDAY, TUESDAY, WEDNESDAY, WEDNESDAY]
enumset:[MONDAY, TUESDAY, WEDNESDAY]

通過結果可以看出ArrayList內放置的元素可以重複,而EnumSet內放置的元素不重複,畢竟是列舉列嘛