Java列舉型別詳解(原理+用法)
阿新 • • 發佈:2018-12-26
可以這麼說,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);
}
}
這只是我的一個個人猜測,不一定正確。