昨天晚上在给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()方法需要两个参数,而这个新增的方法只需要一个参数。