java 枚举的真面目详解编程语言

缘起

在开发中,经常用到枚举,但一直没有认真研究过它。为了更好的理解枚举,决定好好挖掘挖掘。

举个最简单的例子,性别是定数的,可以枚举,所以很容易写出枚举类

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

(0)
上一篇 2021年7月19日
下一篇 2021年7月19日

相关推荐

发表回复

登录后才能评论