1. 程式人生 > >Java列舉型別詳解(原理+用法)

Java列舉型別詳解(原理+用法)

可以這麼說,Java的列舉型別本來是不存在的,但Java發了個"語法糖",就有了列舉型別。Java從JDK1.5開始支援列舉,通常一個特性如果在一開始沒有提供,在語言發展後期才新增,會遇到一個問題,就是向後相容性的問題。像Java在1.5中引入的很多特性,為了向後相容,編譯器會幫我們寫的原始碼做很多事情,比如泛型為什麼會擦除型別,為什麼會生成橋接方法,foreach迭代,自動裝箱/拆箱等,這個術語就叫“語法糖”,而編譯器的特殊處理叫“解語法糖”。那麼像列舉也是在JDK1.5中才引入的,又是怎麼實現的呢?

Java在1.5中添加了java.lang.Enum抽象類,它是所有列舉型別基類。提供了一些基礎屬性和基礎方法。同時,對把列舉用作Set和Map也提供了支援,即java.util.EnumSet和java.util.EnumMap。

那列舉有什麼用呢?其實說白了也就幫你定義一些常量。舉個栗子:

package test;

public enum WeekDay {
	Mon("Monday"), Tue("Tuesday"), Wed("Wednesday"), Thu("Thursday"), 
	Fri("Friday"), Sat("Saturday"), Sun("Sunday");
	  
	/**定義列舉型別自己的屬性**/  
	private final String day;  
	//自己定義構造方法
	private WeekDay(String day) {  
	     this.day = day;  
	}
	//自己定義get方法
	public String getDay() {  
	     return day;  
	}
	  
	/**定義列舉型別自己的方法**/  
	public static void printDay(int i){  
	     switch(i){  
	     case 1: System.out.println(WeekDay.Mon); break;  
	     case 2: System.out.println(WeekDay.Tue);break;  
	     case 3: System.out.println(WeekDay.Wed);break;  
	     case 4: System.out.println(WeekDay.Thu);break;  
	     case 5: System.out.println(WeekDay.Fri);break;  
	     case 6: System.out.println(WeekDay.Sat);break;  
	     case 7: System.out.println(WeekDay.Sun);break;  
	     default:System.out.println("wrong number!");  
	     }  
	}  
	   
}

package test;

public class Main {

	public static void main(String[] args) {
		for (WeekDay day : WeekDay.values()) {  
	         System.out.println(day + "====>" + day.getDay());  
	      }  
	      WeekDay.printDay(5);
	      
//	      貌似編譯器會將列舉裡的屬性值定義成屬性名 可能是覆蓋了toString方法
	      System.out.println(WeekDay.valueOf("Mon")); //輸出Mon
	      System.out.println(WeekDay.Sat); //輸出Sat
	      
	}

}
執行結果:

Mon====>Monday
Tue====>Tuesday
Wed====>Wednesday
Thu====>Thursday
Fri====>Friday
Sat====>Saturday
Sun====>Sunday
Fri
Mon
Sat、

通過上述例子我們很容易發現,列舉型別可以像類一樣定義屬性和方法,非常方便。如果你有什麼常量要儲存的話,可以用列舉。

但列舉既然是語法糖,那它是咋整的呢?

其實他最終也是編譯成一個class檔案的,只是由於是常量和要滿足一些操作,加了static和final修飾。

WeekDay (javap WeekDay 命令之後得到的內容如下去掉了彙編程式碼

public final class WeekDay extends java.lang.Enum{  
    public static final WeekDay Mon;  
    public static final WeekDay Tue;  
    public static final WeekDay Wed;  
    public static final WeekDay Thu;  
    public static final WeekDay Fri;  
    public static final WeekDay Sat;  
    public static final WeekDay Sun;  
    static {};  
    public static void printDay(int);  
    public java.lang.String getDay();  
    public static WeekDay[] values();  
    public static WeekDay valueOf(java.lang.String);  
}  

嗯,就是這樣,其實也沒什麼神奇的吧!不過我們也看到了,枚舉出現了大量static型別,所以不要濫用,不然會無端耗記憶體。但某本神書上寫過,Java列舉型別是實現單例模式的不二神器。

這裡再加上一個我個人的猜測,其實內部列舉值是繼承自外部列舉類的。還是用程式碼來說話吧:

package com.app.test;

/**
 * Created by Tim on 2017/7/14.
 */
public enum TestEnum {
    X("aa", 10) {
        @Override
        public void absFun() { //要實現抽象方法 所以我懷疑內部列舉值是要繼承外部列舉類的
            fun();
        }
    }, Y("aa", 10) {
        @Override
        public void absFun() {
            fun();
        }
    }, Z("aa", 10) {
        @Override
        public void absFun() {
            fun();
        }
    };

    private final String a;
    public final int b;

    public String getA() {
        return a;
    }

    public int getB() {
        return b;
    }

    TestEnum(String a, int b) {

        this.a = a;
        this.b = b;
    }

    public abstract void absFun();

    private void privateFun() {
        System.out.println("Just Fun");
    }

    public void fun() {
        privateFun();
    }

    private static void privateStaFun() {
        System.out.println("static Fun");
    }

    public static void staFun() {
        privateStaFun();
    }

}
package com.app.test;/**
 * Created by Tim on 2017/7/14.
 */

/**
 * create by 陳樟傑
 */
public class Test {
    @org.junit.Test
    public void test() {
        /*TestEnum.staFun();
        TestEnum.X.fun();*/

        TestEnum x = TestEnum.Y;
        x.fun();
        x.absFun();
        x.staFun();

        System.out.println(x.getA()+x.b);
    }
}
這只是我的一個個人猜測,不一定正確。