初學Enum

我有個一個這樣的需要,已知有A、B、C三相位,其中0代表B,1表示A,2表示C,其他參數輸出錯誤。現在有一個入參,輸入一個數字,要求返回對應的相位得到String類型。比如,入參是0,那麼我需要得到 A相 這樣的輸出答案。

筆者之前確實沒有用過Enum,那麼首先,在沒有Enum的情況下,我或許會嘗試這樣去寫代碼:

public class Phase {
	private static String getPhaseStr(int tag) {
		if (tag == 0)
			return "B";
		if (tag == 1)
			return "A";
		if (tag == 2)
			return "C";
		return "錯誤";
	}

	public static void main(String[] args) {
		int input = 0;
		System.out.println(getPhaseStr(input));
	}
}

這樣確實是完成我的需求了。那麼現在,我又有了一個需求,入參是一個String類型的,可能是"A""B""C"要求得出其對應的數字,其他輸入輸出-1,。比如,入參是“A”,出參就應該是1。

ok照着上面代碼的思路,我可以能會這樣去修改代碼:

public class Phase {
	private static String getPhaseStr(int tag) {
		if (tag == 0)
			return "B相";
		if (tag == 1)
			return "A相";
		if (tag == 2)
			return "C相";
		return "錯誤";
	}

	private static int getPhaseTag(String phase) {
		if ("A相".equalsIgnoreCase(phase))
			return 1;
		if ("B相".equalsIgnoreCase(phase))
			return 0;
		if ("C相".equalsIgnoreCase(phase))
			return 2;
		return -1;
	}

	public static void main(String[] args) {
		// int input = 0;
		// System.out.println(getPhaseStr(input));

		String phase = "A相";
		System.out.println(getPhaseTag(phase));

	}
}

好吧,代碼開始變得醜陋了,不過anyway,也完成了我的需求。

好了,那麼現在我又一個新的需求,某某人告訴我,一開始在定義ABC的時候定義錯了,A代表0,B代表1,C代表2。好吧,開始頭大了,那麼我現在或許要考慮我是否需要重新寫下代碼,萬一,到時候某某又告訴我需要加D呢?

public class Phase2 {
	private static Map<Integer, String> map = new HashMap<Integer, String>();

	static {
		map.put(0, "A相");
		map.put(1, "B相");
		map.put(2, "C相");
	}

	private static String getPhaseStr(int tag) {
		String phase=map.get(tag); 
                phase==null?"錯誤":phase;
      }

	private static int getPhaseTag(String phase) {
		for (Map.Entry<Integer, String> e : map.entrySet()) {
			if (phase.equalsIgnoreCase(e.getValue()))
				return e.getKey();
		}
		return -1;
	}
}

確實滿足了我的需求,而且擴展性也變得似乎還不錯。可是我之前在很多框架的源碼裏面有見到Enum,總覺得是個高級貨,所以我也來嘗試用一下:


public enum Phase3 {
	A(0, "A相"), B(1, "B相"), C(2, "C相"), ERROR(-1, "錯誤");

	private int tag;
	private String info;

	private Phase3(int tag, String info) {
		this.tag = tag;
		this.info = info;
	}

	public int getTag() {
		return tag;
	}

	public void setTag(int tag) {
		this.tag = tag;
	}

	public String getInfo() {
		return info;
	}

	public void setInfo(String info) {
		this.info = info;
	}

	public static String getPhaseStr(int tag) {
		for (Phase3 p : Phase3.values()) {
			if (p.getTag() == tag)
				return p.getInfo();
		}
		return ERROR.getInfo();
	}

	public static int getPhaseTag(String s) {
		for (Phase3 p : Phase3.values()) {
			if (s.equalsIgnoreCase(p.getInfo()))
				return p.getTag();
		}
		return ERROR.getTag();
	}

	public static void main(String[] args) {
		int input = 0;
		System.out.println(Phase3.getPhaseStr(input));

		String phase = "A相";
		System.out.println(Phase3.getPhaseTag(phase));
	}

}

小興奮了一把,好像,似乎,確實讓代碼變得更帥氣了,but,還是有個一個問題,無論是getPhaseStr和getPhaseTag,裏面都去循環進行了比較,這點讓我心裏有點不爽快。似乎上,效率還不如Phase2,因爲map通過key查找value的速度是非常快的。

爲了找到答案,筆者特意去學習了下《thinging in java》,或許是我水平不夠,確實有看到一堆例子,但是,實際中,我似乎從來沒有看到過誰這麼使用過,而且其中有個什麼"使用分發",請問分發到底是什麼意思,反正這一段我是看得雲裏霧裏的,而且並沒有發現這樣使用的好處。

但是有一點,我通過javap去反編譯了一下Phase3.class得到以下結果:

public final class myenum.test.Phase3 extends java.lang.Enum<myenum.test.Phase3> {
  public static final myenum.test.Phase3 A;
  public static final myenum.test.Phase3 B;
  public static final myenum.test.Phase3 C;
  public static final myenum.test.Phase3 ERROR;
  static {};
  public int getTag();
  public void setTag(int);
  public java.lang.String getInfo();
  public void setInfo(java.lang.String);
  public static java.lang.String getPhaseStr(int);
  public static int getPhaseTag(java.lang.String);
  public static void main(java.lang.String[]);
  public static myenum.test.Phase3[] values();
  public static myenum.test.Phase3 valueOf(java.lang.String);
}

1.enum裏面的最終被編譯成了:public static final myenum.test.Phase3 A;  每一個枚舉裏面的類型都被編譯成一個Phase3的對象,而且extends了java.lang.Enum。這就意味着Phase3裏面的所有的方法都可以使用。結論就是,把enum裏面的每個類型都看作一個對象吧,它可以實現接口,但是不能extend。

2.通過學習,Phase3還可以寫成這樣:

public enum Phase4 {
	A(0) {
		@Override
		public String getInfo() {
			return "A相";
		}
	},
	B(1) {
		@Override
		public String getInfo() {
			return "B相";
		}

	},
	C(2) {
		@Override
		public String getInfo() {
			return "C相";
		}

	},
	ERROR(-1) {

		@Override
		public String getInfo() {
			return "錯誤";
		}

	};

	private int tag;

	private Phase4(int tag) {
		this.tag = tag;
	}

	public int getTag() {
		return tag;
	}

	public void setTag(int tag) {
		this.tag = tag;
	}

	public abstract String getInfo();

	public static String getPhaseStr(int tag) {
		for (Phase4 p : Phase4.values()) {
			if (p.getTag() == tag)
				return p.getInfo();
		}
		return ERROR.getInfo();
	}

	public static int getPhaseTag(String s) {
		for (Phase4 p : Phase4.values()) {
			if (s.equalsIgnoreCase(p.getInfo()))
				return p.getTag();
		}
		return ERROR.getTag();
	}

	public static void main(String[] args) {
		int input = 0;
		System.out.println(Phase4.getPhaseStr(input));

		String phase = "A相";
		System.out.println(Phase4.getPhaseTag(phase));
	}

}
這段代碼的精髓在於這個abstract,可見枚舉的對象還可以有自己的方法。

3.在操作枚舉類型的時候,可能會用到EnumMap和EnumSet

4.《Thinking in Java》中Enum的那些Enum看不懂的地方,直接忽略吧。使用Enum最初的功能就好。

5.使用Enum並不能使代碼的效率更高,但是他能讓代碼的更加的優雅帥氣。接下來在日常的代碼中儘量多用吧,或許多用會有不同的體會。


另外在書中有看到幾個有意思的東西:

1.靜態導入包 import static ****;

2.System.getenv("")可以獲取環境變量System.getProperties(“java.version”)可以獲取java版本

3.書中有提到用Enum實現職責鏈(Chain of Responsibility),這個是不是很像mina的handler,一層一層的提交。










發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章