java基礎加強--實現帶有抽象方法的列舉
在學列舉的時候,看到這樣定義列舉感到很奇怪。
public enum WeekDay {
SUN,MON,TUE,WED,THI,FRI,SAT
}
感覺像一個類,但又不是類。。
想看一下這個被編譯過的位元組碼檔案裡都是什麼內容。。
javac WeekDay.java在被編譯後生成了WeekDay.class檔案。
然後反編譯javap WeekDay
Compiled from "WeekDay.java" public final class WeekDay extends java.lang.Enum<WeekDay> { public static final WeekDay SUN; public static final WeekDay MON; public static final WeekDay TUE; public static final WeekDay WED; public static final WeekDay THI; public static final WeekDay FRI; public static final WeekDay SAT; public static WeekDay[] values(); public static WeekDay valueOf(java.lang.String); static {}; }
會發現原來public enum WeekDay被編譯器編譯成了
public final class WeekDay extends java.lang.Enum<WeekDay>
所以列舉就相當於一個類,而且是final 的最終類。繼承自java.lang.Enum。
列舉值SUN被編譯器編譯成了
public static final WeekDay SUN; 這是一個靜態常量,型別是WeekDay。
--------------
那麼靜態常量的初始化在哪裡?
檢視Java API會發現java.lang.Enum有個建構函式
構造方法摘要 |
|
protected |
Enum |
既然WeekDay 是個列舉類,肯定繼承了java.lang.Enum。
WeekDay是Enum的子類,子類能呼叫父類的建構函式進行初始化。
列舉型別的每一個值都將對映到 protected Enum(String name, int ordinal) 建構函式中,在這裡,每個值的名稱都被轉換成一個字串,並且序數設定表示了此設定被建立的順序。
public enum WeekDay {
SUN,MON,TUE,WED,THI,FRI,SAT
}
這段程式碼實際上呼叫了7次 Enum(String name, int ordinal)
newEnum<WeekDay>("SUN",0); newEnum<WeekDay>("MON",1); newEnum<WeekDay>("TUE",2); ... ... |
可以把 enum 看成是一個普通的 class,它們都可以定義一些屬性和方法。
不同之處是:enum 不能使用 extends 關鍵字繼承其他類,因為 enum 已經繼承了 java.lang.Enum(java是單一繼承)。
WeekDay繼承了java.lang.Enum,當然也能使用Enum的方法。
方法摘要 |
||
protected |
clone() |
|
int |
(E o) |
|
boolean |
( other) |
|
protected void |
() |
|
() |
||
int |
() |
|
name() |
||
int |
() |
|
static
|
(Class<T> enumType, name) |
--------------
列舉也相當於一個類。當然也可以定義自己的建構函式。但是這個建構函式必須為private所修飾。
這樣可以保證外部程式碼無法新構造列舉類的例項。
public enum WeekDay {
SUN,MON,TUE,WED,THI,FRI,SAT;
private WeekDay(){
System.out.println(this.name()+"被初始化");
}
public static void main(String[] args){
WeekDay wd = WeekDay.FRI;
}
}
結果輸出:
SUN被初始化
MON被初始化
TUE被初始化
WED被初始化
THI被初始化
FRI被初始化
SAT被初始化
WeekDay內部的SUN,MON,TUE,WED,THI,FRI,SAT;等靜態常量一一被初始化。
------------
WeekDay相當於類當然也可以定義自己的成員(包括成員方法和成員函式):
public enum WeekDay {
SUN,MON,TUE,WED,THI,FRI,SAT;
private int ss = 9;
private WeekDay(){
// System.out.println(this.name()+"被初始化");
}
public static void main(String[] args){
WeekDay wd = WeekDay.FRI;
wd.vv();
wd = WeekDay.MON;
wd.vv();
WeekDay.SAT.vv();
}
public void vv(){
System.out.println("vvvvv"+(++ss));
}
}
結果輸出:
vvvvv10
vvvvv10
vvvvv10
----------------
發現使用幾個列舉值輸出的結果都是一樣的。
能不能讓每個列舉值輸出的結果不同呢?
於是就想到了多型
由父類引用指向子類物件,子類重寫父類的方法。在執行的時候,實際呼叫的是子類的方法。
--------------
在一個類裡怎麼讓父類引用指向子類物件呢?
可以使用匿名內部類。
父類的方法不具體,子類重寫父類方法後各自實現的也不同,所以將父類的方法定義為抽象的。父類的方法是抽象的了,當然父類也得是抽象類了。
例子:
public abstract class ListDemo {
ListDemo dd = new ListDemo(){ //new ListDemo()是什麼具體的類?不知道,只知道是ListDemo的子類。。
//所以new ListDemo()是匿名內部類
public void zz() {
}
};
public abstract void zz();
}
-------------------------
可以再擴充套件下:
public abstract class TrafficLamp{
//RED是TrafficLamp類的成員,是TrafficLamp類的一個引用;
/* ---------
* new TrafficLamp(){
* public TrafficLamp nextLamp() {
return GREEN;
}
* };就是匿名內部類,是TrafficLamp的子類物件。
*/
public static final TrafficLamp RED = new TrafficLamp(){
public TrafficLamp nextLamp() {
return GREEN;
}
};
public static final TrafficLamp GREEN = new TrafficLamp(){
public TrafficLamp nextLamp() {
return YELLOW;
}
};
public static final TrafficLamp YELLOW = new TrafficLamp(){
public TrafficLamp nextLamp() {
return RED;
}
};
public abstract TrafficLamp nextLamp();
}
使用javac TrafficLamp.java編譯這個程式得到4個class檔案
類名$數字就代表一個匿名內部類。
-----------
會發現上面的TrafficLamp 怎麼那麼像列舉呢?
它和列舉比較相似。
那麼在列舉中能不能定義抽象方法,並由子類實現呢?
當然是可以的。功能是一樣的,而且實現起來會更簡單。
public enum TrafficLamp{
/* RED是列舉的一個元素,
* 這個元素可以看做是由TrafficLamp的一個子類來實現的。
* */
RED{
public TrafficLamp nextLamp() {
return GREEN;
}
},
GREEN{
public TrafficLamp nextLamp() {
return YELLOW;
}
},
YELLOW{
public TrafficLamp nextLamp() {
return RED;
}
};
public abstract TrafficLamp nextLamp();
}
使用javac TrafficLamp.java編譯這個程式
最後也是得到4個class檔案
這就是實現帶有抽象方法的列舉。
如果一下子就看到這樣帶有抽象方法的列舉會感到很突兀,不知從何而來,為什麼這樣寫呢。有了以上分析的會感覺好懂些。