学习JDK5的枚举类型

昨天晚上在给Struts2的Action写测试代码的时候,需要用到enum,就研究了一下。
先是enum的代码:
代码段1:
public enum ActionResult {

	SUCCESS("success"),
	NONE("none"),
	ERROR("error"), 
	INPUT("input"),
	LOGIN("login");

	private String value;
	
	private ActionResult(String value){
		this.value = value;
	}
	
	/**
	 * 返回常量值
	 * @return 常量值
	 */
	public String getValue(){
		return value;
	}
}

试着输出ActionResult.SUCCESS:
System.out.println(ActionResult.SUCCESS);

结果:
引用
SUCCESS


输出ActionResult.SUCCESS.getClass():
System.out.println(ActionResult.SUCCESS.getClass());

结果:
引用
class net.javayuan.blog.constant.ActionResult


给ActionResult加上main方法,检查ActionResult的类型:

public enum ActionResult {

	SUCCESS("success"),
	NONE("none"),
	ERROR("error"), 
	INPUT("input"),
	LOGIN("login");
	
	private String value;
	
	private ActionResult(String value){
		this.value = value;
	}
	
	/**
	 * 返回常量值
	 * @return 常量值
	 */
	public String getValue(){
		return value;
	}
	
	public static void main(String[] args){
		Class<?> clazz = ActionResult.class;
		Class<?> superClass = clazz.getSuperclass();
		Class<?>[] interfaces = clazz.getInterfaces();
		System.out.println(clazz);
		System.out.println(superClass);
		System.out.println(interfaces.length);
	}
}

输出:
引用
class net.javayuan.blog.constant.ActionResult
class java.lang.Enum
0

结论:1、enum关键字定义的枚举类型的直接父类都是java.lang.Enum。至于Enum的父类,查查API文档就知道了:Enum的父类是Object。
2、enum关键字定义的枚举类型没有直接实现任何接口。查了API文档,Enum实现了Serializable接口跟Comparable接口。
已知:ActionResult.SUCCESS.getClass().toString()的结果是"class net.javayuan.blog.constant.ActionResult",
并且ActionResult的父类是Enum,接着来看看为什么System.out.println(ActionResult.SUCCESS);输出"SUCCESS"。

打开java.lang.Enum的源代码,查找关键字“public String toString()”,找到代码:
public String toString() {
    return name;
}


name的定义:
private final String name;

name的赋值在Enum的protected构造方法中执行:
protected Enum(String name, int ordinal) {
    this.name = name;
    this.ordinal = ordinal;
}

给ActionResult的main方法中添加一句代码:System.out.println(ActionResutl.SUCCESS)
	public static void main(String[] args){
		Class<?> clazz = ActionResult.class;
		Class<?> superClass = clazz.getSuperclass();
		Class<?>[] interfaces = clazz.getInterfaces();
		System.out.println(clazz);
		System.out.println(superClass);
		System.out.println(interfaces.length);

		System.out.println(ActionResult.SUCCESS);
	}

在Enum的构造方法处和ActionResult的main方法处同时设置断点,检查Enum的构造是在什么时候执行。结果用Eclipse调试的时候意外的发现,Enum的构造在main方法执行之前。查看Enum构参数中name和ordinal的值,居然name为null,那toString中的name是怎么来的?继续调试,发现执行完this.name = name;之后,参数列表中的name跟Enum中的name同时变成了"SUCCESS",这个值是怎么来的,我也无从查证,因为构造Enum时,参数name居然是未知的,我只能猜测是JVM对Enum进行了特殊处理。再调试了几遍,发现第二个构造参数ordinal也一样(它也是Enum类的一个私有int常量),执行this.ordinal = ordinal;之后,它的值才确定。按F7跳出Enum的构造方法,结果跳到ActionResult的构造方法里,检查参数value,值为"success"。按F7,跳到了SUCCESS("success");这一行。按F5,发现SUCCESS("success")刚执行完毕,原来刚刚的动作是对SUCCESS进行初始化。现在箭头指在NONE("none")这一行,按F5,进入ActionResult构造方法,再按F5,进入了Enum构造方法,执行完Enum的构造,检查一下ordinal的值,为1。初始化ERROR时,ordinal为2。
结论:
1、SUCCESS、NONE等静态变量是常量;
2、ActionResult的构造是在对常量SUCCESS、NONE等进行初始化时执行,每个常量都是一个ActionResult实例;
3、ActionResult构造之前会调用Enum的构造方法,对Enum进行构造(看来之前写的 关于构造方法对enum不适用);
4、构造Enum时,参数name和ordinal的值都是未知的,name值似乎是来自常量名,ordinal从0开始递增,ordinal具体作用目前不明;

翻了Thinking In Java 4th Edition:
引用
ordinal()方法返回一个int值,这是每个enum实例在声明时的次序,从0开始。

引用
values()是由编译器添加的static方法。可以看出,在创建Explore的过程中,编译器还为其添加了valueOf()方法。这可能有点令人迷惑,Enum类不是已经有valueOf()方法了吗。不过Enum中的valueOf()方法需要两个参数,而这个新增的方法只需要一个参数。

你可能感兴趣的:(eclipse,jvm,.net,Blog)