缘起
在开发中,经常用到枚举,但一直没有认真研究过它。为了更好的理解枚举,决定好好挖掘挖掘。
举个最简单的例子,性别是定数的,可以枚举,所以很容易写出枚举类
public enum SexEnum {
MAN(11,"男"),
WOMAN(12,"女");
private Integer code;
private String myname;
SexEnum(Integer code, String name) {
this.code = code;
this.myname = name;
}
//getter and setter
}
问题
写完后,不禁想到几个问题
SexEnum.values()方法从何而来,Enum抽象类中并不存在values()方法
MAN和WOMAN是SexEnum对象,有get/set方法,我们只是写了一个文本MAN、WOMAN,它怎么就变成了对象?是怎么实现的?
还有一点你也许没有注意,构造方法的修饰符只能是默认或private,不能是protected、public的,这是为什么?
为了一探究竟,将类反编译
public final class SexEnum extends Enum
{
public static SexEnum[] values()
{
return (SexEnum[])$VALUES.clone();
}
public static SexEnum valueOf(String name)
{
return (SexEnum)Enum.valueOf(com/jun/javase/SexEnum, name);
}
private SexEnum(String s, int i, Integer code, String name)
{
super(s, i);
this.code = code;
myname = name;
}
public static final SexEnum MAN;
public static final SexEnum WOMAN;
private Integer code;
private String myname;
private static final SexEnum $VALUES[];
static
{
MAN = new SexEnum("MAN", 0, Integer.valueOf(11), "/u7537");
WOMAN = new SexEnum("WOMAN", 1, Integer.valueOf(12), "/u5973");
$VALUES = (new SexEnum[] {
MAN, WOMAN
});
}
//setter and getter
}
看到反编译后代码,恍然大悟,说到底,枚举又是一个语法糖就跟泛型一样。
values()方法从何而来
SexEnum .values()方法从何而来,Enum接口中并不存在values()方法。
values()方法的返回值来源于变量$VALUES
,而$VALUES
是包含MAN和WOMAN的数组,java编译器创建了values方法
枚举变量如何变成了对象
MAN和WOMAN有getCode/setCode/getMyname/setMyname方法,由此可以退款,它是SexEnum 对象,我们只是写了一个文本,它怎么就变成了对象?是怎么实现的?
从代码中可以看出,MAN和WOMAN被定义成了SexEnum 类型的变量,并且在静态代码块中赋了值,名字是MAN,次序是0,code是11,myname是"/u7537"
。这也解答了Enum api中的ordinal()
方法和name()
方法。既然MAN和WOMAN是final static的,所以比较时可以使用==
这也让我弄明白了java核心卷中说的枚举比较使用==
的原因了。从中可以还出还是java编译器捣的鼓^_^
public static final SexEnum MAN;
public static final SexEnum WOMAN;
MAN = new SexEnum("MAN", 0, Integer.valueOf(11), "/u7537");
WOMAN = new SexEnum("WOMAN", 1, Integer.valueOf(12), "/u5973");
构造方法范围为什么只能是private或默认
构造方法的修饰符只能是默认或private,不能是protected、public的,这是为什么?
这是因为枚举相当于util类,没有必要多例,最好单例,实现单例的第一要素肯定是private构造方法,所以从反编译后的构造方法是private的,所以,我们将枚举类的构造方法设置为public会编译报错。
private SexEnum(String s, int i, Integer code, String name)
{
super(s, i);
this.code = code;
myname = name;
}
总结
枚举归根到底是一个语法糖,它能让我们更容易、更快速写出常量定义,并且更加直观安全。
java编译器将定义的枚举,都转换成对象,并且在static代码块中创建了对象并将所有枚举值放入了一个临时变量中,创建了values()方法。java编译器创建了一个参数是名字、次序、自定义参数的构造方法,并且范围是private,所以才有了枚举的特性。
关于枚举相比常量更加直观、更加安全,这一点这里举个例子,比如设置性别方法,如果使用常量方式,我们就得这样写
public void setSex(int value){
}
value值的取值范围就不好限制了,当然你会说,在方法中判断,这样当然可以达到目的,但有点繁琐。
我们看看枚举的方式
public void setSex(SexEnum sex){
}
这样sex只能是性别,其他值都会编译错误,一眼就能懂是性别,而且更加安全。
原创文章,作者:Maggie-Hunter,如若转载,请注明出处:https://blog.ytso.com/20259.html