1. 程式人生 > >java基礎加強--實現帶有抽象方法的列舉

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

( name, int ordinal)
          單獨的構造方法。

既然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.Enumjava是單一繼承)。

WeekDay繼承了java.lang.Enum,當然也能使用Enum的方法。

方法摘要

protected  

clone()
          丟擲 CloneNotSupportedException。

 int

(E o)
          比較此列舉與指定物件的順序。

 boolean

( other)
          當指定物件等於此列舉常量時,返回 true。

protected  void

()
          列舉類不能有 finalize 方法。

 Class<E>

()
          返回與此列舉常量的列舉型別相對應的 Class 物件。

 int

()
          返回列舉常量的雜湊碼。

name()
          返回此列舉常量的名稱,在其列舉宣告中對其進行宣告。

 int

()
          返回列舉常量的序數(它在列舉宣告中的位置,其中初始常量序數為零)。

static

<T extends Enum<T>>
 T

(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編譯這個程式得到4class檔案

 

類名$數字就代表一個匿名內部類。

-----------

會發現上面的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編譯這個程式

最後也是得到4class檔案


這就是實現帶有抽象方法的列舉。

如果一下子就看到這樣帶有抽象方法的列舉會感到很突兀,不知從何而來,為什麼這樣寫呢。有了以上分析的會感覺好懂些。