我有個一個這樣的需要,已知有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,一層一層的提交。