java枚舉詳解


一、簡介

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);
    }

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

二、7種常見的用法

用法一:常量
  在JDK1.5 之前,我們定義常量都是: public static fianl.... 。現在好了,有了枚舉,可以把相關的常量分組到一個枚舉類型里,而且枚舉提供了比常量更多的方法。

1 public enum Color { 
2     RED, GREEN, BLANK, YELLOW 
3 }

用法二:switch

 1 enum Signal {  
 2     GREEN, YELLOW, RED  
 3 }  
 4 public class TrafficLight {  
 5     Signal color = Signal.RED;  
 6     public void change() {  
 7         switch (color) {  
 8         case RED:  
 9             color = Signal.GREEN;  
10             break;  
11         case YELLOW:  
12             color = Signal.RED;  
13             break;  
14         case GREEN:  
15             color = Signal.YELLOW;  
16             break;  
17         }  
18     }  
19 } 

用法三:向枚舉中添加新方法

 1 public enum Color {  
 2     RED("紅色", 1), GREEN("綠色", 2), BLANK("白色", 3), YELLO("黃色", 4);  
 3     // 成員變量  
 4     private String name;  
 5     private int index;  
 6     // 構造方法  
 7     private Color(String name, int index) {  
 8         this.name = name;  
 9         this.index = index;  
10     }  
11     // 普通方法  
12     public static String getName(int index) {  
13         for (Color c : Color.values()) {  
14             if (c.getIndex() == index) {  
15                 return c.name;  
16             }  
17         }  
18         return null;  
19     }  
20     // get set 方法  
21     public String getName() {  
22         return name;  
23     }  
24     public void setName(String name) {  
25         this.name = name;  
26     }  
27     public int getIndex() {  
28         return index;  
29     }  
30     public void setIndex(int index) {  
31         this.index = index;  
32     }  
33 }

用法四:覆蓋枚舉的方法

下面給出一個toString()方法覆蓋的例子。

 1 public enum Color {  
 2     RED("紅色", 1), GREEN("綠色", 2), BLANK("白色", 3), YELLO("黃色", 4);  
 3     // 成員變量  
 4     private String name;  
 5     private int index;  
 6     // 構造方法  
 7     private Color(String name, int index) {  
 8         this.name = name;  
 9         this.index = index;  
10     }  
11     //覆蓋方法  
12     @Override  
13     public String toString() {  
14         return this.index+"_"+this.name;  
15     }  
16 } 

用法五:實現接口

  所有的枚舉都繼承自java.lang.Enum類。由於Java 不支持多繼承,所以枚舉對象不能再繼承其他類。

 1 public interface Behaviour {  
 2     void print();  
 3     String getInfo();  
 4 }  
 5 public enum Color implements Behaviour{  
 6     RED("紅色", 1), GREEN("綠色", 2), BLANK("白色", 3), YELLO("黃色", 4);  
 7     // 成員變量  
 8     private String name;  
 9     private int index;  
10     // 構造方法  
11     private Color(String name, int index) {  
12         this.name = name;  
13         this.index = index;  
14     }  
15 //接口方法  
16     @Override  
17     public String getInfo() {  
18         return this.name;  
19     }  
20     //接口方法  
21     @Override  
22     public void print() {  
23         System.out.println(this.index+":"+this.name);  
24     }  
25 }

用法六:使用接口組織枚舉

1 public interface Food {  
2     enum Coffee implements Food{  
3         BLACK_COFFEE,DECAF_COFFEE,LATTE,CAPPUCCINO  
4     }  
5     enum Dessert implements Food{  
6         FRUIT, CAKE, GELATO  
7     }  
8 }

用法七:關於枚舉集合的使用

java.util.EnumSet和java.util.EnumMap是兩個枚舉集合。EnumSet保證集合中的元素不重復;EnumMap中的 key是enum類型,而value則可以是任意類型。關於這個兩個集合的使用就不在這里贅述。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM