初学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,一层一层的提交。










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