查看原文
其他

Java中的枚举类型(Enum)详解

易哥 架构研究所 2022-09-08
文章前记

       

 程序员工作久了便可能整日忙碌于“增删改查”中,迷失方向,毫无进步。


        该公众号致力于分享软件开发相关的原创干货,助你完成从程序员到架构师的进阶之路!


        努力!做一个NB的Coder!









1枚举类型初探



枚举类型,其语法总让人觉着怪怪的,如下:



简单的一行,就定义了包含四个值的枚举类型,缺总让人觉着语法有点怪异。而在使用时:



就可以得到输出:



那我们简单的一行定义中,到底发生了什么?枚举类型在编译时是怎样实现的?它还有着怎样的特点?


我们将会分几节对Java中的枚举类型进行介绍。





2枚举产生之前




如果不使用枚举,我们要对“春夏秋冬”这四个值分别赋予一个数字,则常见的操作为:



上述方法定义十分繁琐,而且容易出错。例如我们定义的int数字出现重复,编译器也不会给出任何的警示。同时,这样的操作是实在太频繁了,最终Java 5中增加了枚举类型。


而是用枚举类型后,一切就变成了如下所示的简单几行:



而且,Java自动给按照枚举值出现的顺序,从0开始分配了编号。通过name()可以获得枚举值的名称,通过ordinal()可以获得枚举值的编号。





3枚举实现原理




那我们定义枚举类型后,到底发生了什么呢?我们对枚举的实现原理进行探究。


首先,我们在实现Season枚举类时,并没有定义name()和ordinal()方法。我们从这里入手,点击该方法后,发现进入了一个抽象类:



并且,我们发现编译器不允许我们自行实现该抽象类从而构造一个新的类。但是,既然我们的Season枚举类可以调用其中的方法,因此Season枚举类应该是继承了该抽象类。


为了验证这一猜想,我们让Season类继承一个其他的类,发现果然不可以,因为Java是不允许多继承的。


具体,我们对Season类进行反编译,即:java -p Season.class,得到反编译后的结果:



我们看到,对与枚举类,有很多值的注意的点:


  • 枚举类在经过编译后确实是生成了一个扩展了java.lang.Enum的类


  • 枚举类是final的,因此我们无法再继承它了


  • 我们定义的每个枚举值都是该类中的一个成员,且成员的类型仍然是Season类型


  • 枚举类中被默认增加了许多静态方法,例如values()等


为了进一步了解每个方法中的操作,我们使用java -p -c Season.class每个方法中的字节码:



根据字节码,我们还原其操作代码,大致如下:


注意:以下代码为笔者自己翻译,如果有好的字节码查看工具请一定要留言告诉我啊。



通过这里我们可以看到,在类的static操作中,编译器帮助我们生成每个枚举值的对象。





4总结




我们在总结一下,我们使用enum定义的枚举类型,会在编译之后转化为一个继承了java.lang.Enum的类,而我们定义的每个枚举值都会在类的初始化阶段被实例化为我们所定义的枚举类的一个对象。


同时,编译器还帮我们在类中增加了两个方法,分别是:values()和valueOf()。


至此,我们对Java的枚举对象有了彻底的认识。


但是,我们依旧有着很多的疑惑:


  • 编译器插入的方法和正常的方法有无不同


  • 枚举类型还有哪些使用上的注意点,例如相关方法和操作


  • 枚举类型的实现上还有哪些特殊之处


这些,我们在接下来的文章中继续分析。




END






您可能也对以下帖子感兴趣

文章有问题?点此查看未经处理的缓存