引言

文章相关代码已收录至我的github,欢迎star:lsylulu/myarticle
枚举类可能在初学者的知识储备中比较陌生,但实际开发中,枚举类又不可或缺。枚举类能够统一管理一些全局的变量,封装对于他们的逻辑与方法。还能和switch-case结合,简化大量的if-else,让代码更加优雅。
本文将从以下几个角度介绍枚举类:

  • 枚举类的作用
  • 枚举类基本性质
  • 枚举类基本方法
  • 含有抽象方法的枚举类
  • 枚举类的编译原理
  • 枚举类版单例模式
  • 结合反射获取枚举实例及属性

一、为什么要用枚举类

关于这个问题,网上的答案很多,我大概整理一下。

1)出于类型安全考虑,没用枚举类之前,常用静态常量来表示。
比如对于性别的表示,
public static final MAN = 0; 
public static final WOMAN = 1; 
这样的性别定义实际上是一个整型数据,其一,这些变量完全可用来做加减运算,当然我们原意并非如此;其二,意义不明,当我们debug的时候,本来向输出‘男’,结果输出0。于是我们不得不去前面寻找0表示的意义,特别是看别人的代码时,会很懵逼。

2)代码更优雅
一个大一些的程序里面,可能要用到成百上千的静态常量,如果全写在一个文件里面,容易造成命名混淆,程序读起来也比较麻烦。

3)枚举类能方便我们定义自己想要的类型
枚举便于记忆和使用,并且相当于一个接口。使用时只需要封装内部的数据类型,并且限定数据域。而且对于不同的枚举变量,可以调用不同的处理方法(实现枚举类的抽象方法可以做到这一点)。

二、枚举类的定义及其内部方法讲解

如果不能充分的理解枚举类的作用,不要担心,看完后就明白啦~

2.1 枚举类基础

public enum Week {//本文的枚举类变量,枚举类实例,name属性指的就是MONDAY//这类的变量MONDAY("星期一"),TUESDAY("星期二"),WEDNESDAY("星期三"),THURSDAY("星期四"),FRIDAY("星期五"),SATURDAY("星期六"),//最后一个类型必须要用分号结束SUNDAY("星期日");private int num;private String desc;/*** 构造方法必然是private修饰的* 就算不写,也是默认的** @param num* @param desc*/private Week(int num, String desc) {this.num=num;this.desc = desc;}public String getDesc() {return desc;}public int getNum() {return num;}

定义了一个简单了关于星期的枚举类,如果是第一次见,也不要着急,看多了就会写了。
看完代码,就从关于枚举类的基础开始讲解。
1)使用enum定义的枚举类默认继承了java.lang.Enum,实现了java.lang.Comparable接口,且不能继承其他类,也不可以被继承。但枚举类可以实现一个或多个接口。想深入学习必须挖Enum的源码。
2)枚举类的所有实例必须放在第一行显示,不需使用new,不需显示调用构造方法,每个变量都是public static final修饰的,最终以分号结束。在之后的反编译中,我们就可以理解枚举类其实也是颗语法糖。
3)枚举类的构造方法是私有的,默认的就是private,定义的时候不加也没事。
4)switch()参数可以使用enum。这个在后文有详细代码。
5)非抽象枚举类默认是final的但定义的时候加上final却编译不通过。我们通过后续的反编译可以得到验证。
6)枚举类可以有抽象方法,但是必须在它的实例中实现。后续也会验证这一条。

2.2 name成员变量和常用方法

记下我在这挖的几个坑,先来看看枚举类的name成员变量和常用方法。

2.2.1 name成员变量和常用方法

name成员变量

2.2.2 枚举类的常用方法

  • valueOf()

返回当前枚举类的name属性,如果没有,则throw new java.lang.IllegalArgumentException()。具体可以查看java.lang.Enum源码。

  • values()

编译器自动生成的方法,Enum中并没有该方法,返回包括所有枚举变量的数组。

  • toString(),name()

很简单,两个方法一样,返回当前枚举类变量的name属性。
如果默认的toString()不能满足需求,我们可以结合switch来灵活的实现toString()方法

    /*** 用switch重写toString方法,提高代码健壮性* @return*/@Overridepublic String toString() {//switch支持Enum类型switch (this) {case MONDAY:return "今天星期一";case TUESDAY:return "今天星期二";case WEDNESDAY:return "今天星期三";case THURSDAY:return "今天星期四";case FRIDAY:return "今天星期五";case SATURDAY:return "今天星期六";case SUNDAY:return "今天星期日";default:return "Unknow Day";}}
  • ordinal()

枚举类会给所有的枚举变量一个默认的次序,该次序从0开始,是根据我们定义的次序来排序的。而ordinal()方法就是获取这个次序(或者说下标)。

  • compareTo()

比较的是两个枚举变量的次序,返回两个次序相减后的结果,具体可以扒源码。

看看如下示例:

    public static void main(String[] args) {//通过values()获取枚举数组Week[] weeks = Week.values();//遍历Week枚举类for (Week day : weeks) {System.out.println("name:" + day.name() +",desc:" + day.getDesc());}//不符合则抛出java.lang.IllegalArgumentExceptionSystem.out.println(Week.valueOf("MONDAY"));//返回对应的name属性System.out.println(Week.FRIDAY.toString());//返回4,根据我们定义的次序,从0开始。如果在定义时调换FRIDAY//的次序,返回的数字也会对应的变化System.out.println(Week.FRIDAY.ordinal());}

输出:

name:MONDAY,desc:星期一
name:TUESDAY,desc:星期二
name:WEDNESDAY,desc:星期三
name:THURSDAY,desc:星期四
name:FRIDAY,desc:星期五
name:SATURDAY,desc:星期六
name:SUNDAY,desc:星期日
今天星期一
今天星期五
4

2.3 含有抽象方法的枚举类

如果写抽象方法,枚举类的所有实例必须实现抽象方法。MONDAY本身就是一个AbstractWeek对象的引用。在初始化这个枚举类的时候,等同于执行的是AbstractWeek MONDAY= new AbstractWeek(0,"星期一")。然后用匿名内部类的方式实现getNextDay()。

/*** 枚举类可以有抽象方法,但是必须在它的实例中实现*/
public enum AbstractWeek {MONDAY(0,"星期一") {@Overridepublic AbstractWeek getNextDay() {return TUESDAY;}}, TUESDAY(1,"星期二") {@Overridepublic AbstractWeek getNextDay() {return WEDNESDAY;}}, WEDNESDAY(2,"星期三") {@Overridepublic AbstractWeek getNextDay() {return THURSDAY;}}, THURSDAY(3,"星期四") {@Overridepublic AbstractWeek getNextDay() {return FRIDAY;}}, FRIDAY(4,"星期五") {@Overridepublic AbstractWeek getNextDay() {return SATURDAY;}}, SATURDAY(5,"星期六") {@Overridepublic AbstractWeek getNextDay() {return SUNDAY;}}, SUNDAY(6,"星期日") {@Overridepublic AbstractWeek getNextDay() {return MONDAY;}};private int num;private String desc;AbstractWeek(int num,String desc) {this.num = num;this.desc=desc;}//一个抽象方法public abstract AbstractWeek getNextDay();public static void main(String[] args) {String nextDay=AbstractWeek.MONDAY.getNextDay().toString();System.out.println(nextDay);}
}

编译后所有实例都会成为内部类,相当于每个实例用匿名内部类的形式实现getNextDay的方法。如:

AbstractWeek MONDAY= new AbstractWeek (){@Overridepublic AbstractWeek getNextDay() {return TUESDAY;}
};

三、为什么说枚举类是语法糖

这个问题需要从原理角度阐述,我们通过反编译来查看AbstractWeek,可以发现继承了Enum,里面的所有成员变量都是public static final修饰的!而且values()方法是编译器生成的。其实每一个实例都是一个内部类,在项目路径下会生成AbstractWeek$1.class-AbstractWeek$7.class。每个内部类又都实现了getNextDay()方法。因此,定义枚举实例的时候代码如此的优雅,完全是语法糖给我们的甜头呀!

public abstract class AbstractWeek extends java.lang.Enum<AbstractWeek> {public static final AbstractWeek MONDAY;public static final AbstractWeek TUESDAY;public static final AbstractWeek WEDNESDAY;public static final AbstractWeek THURSDAY;public static final AbstractWeek FRIDAY;public static final AbstractWeek SATURDAY;public static final AbstractWeek SUNDAY;public static solution1.AbstractWeek[] values();Code:0: getstatic     #2                  // Field $VALUES:[Lsolution1/AbstractWeek;3: invokevirtual #3                  // Method "[Lsolution1/AbstractWeek;".clone:()Ljava/lang/Object;6: checkcast     #4                  // class "[Lsolution1/AbstractWeek;"9: areturn
......
}

四、枚举版单例与反射获取枚举对象

4.1 学会枚举创建单例模式

我们可以充分利用枚举默认构造方法私有化的性质来实现单例。由于里面的成员变量都是final修饰的,因此不会有线程不安全的问题。
枚举类版的单例模式,就是这么简单。

       public enum EnumSingleton{INSTANCE;}

4.2 反射获取枚举对象

        // 1.得到枚举类对象Class<?> clazz = AbstractWeek.class;// 2.得到枚举类中的所有实例Object[] enumInstances = clazz.getEnumConstants();Method getDesc= clazz.getMethod("getDesc");Method getNextDay= clazz.getMethod("getNextDay");for (Object instance : enumInstances){// 3.调用对应方法,得到枚举类中实例的值与实现的抽象方法System.out.println("desc=" + getDesc.invoke(obj) + "; nextDay=" + getNextDay.invoke(obj));}

总结

本文主要讲述了枚举的作用,语法,基本方法,实现抽象方法,实现原理,单例与反射。我在2.1中挖的坑也都填上了。真正吸收的话还得多看多练。掌握了这些,在实际编码的时候也会舒坦些。网上的博客对于枚举的知识都比较零碎,自我感觉搬运的干货还是比较全面的。

文章若有不当之处,欢迎评论指出~
如果喜欢我的文章,欢迎关注我的知乎专栏Java修仙道路~

参考文章:Enum详解

Java枚举类,你真的了解吗?相关推荐

  1. Java枚举类使用方式

    Java枚举类使用方式 单枚举定义 : /*** * @title: 单枚举定义* @author: wll* @since: 2021-1-27 14:47:54*/ public enum Jud ...

  2. 比起睡觉,我更喜欢刷巨详细的Java枚举类,这是来自猿人的自觉呀

    零基础学习之Java枚举类 概述 JDK1.5之前 创建枚举类 代码示例 JDK1.5之后 创建枚举类 代码示例 枚举类继承父类 基本介绍 代码示例 枚举类实现接口 基本介绍 代码示例 枚举类实现单例 ...

  3. 学妹问我Java枚举类与注解,我直接用这个搞定她!

    很多人问我学妹长什么样,不多说 上图吧! 学妹问我Java枚举类与注解,我直接一篇文章搞定! 一.枚举类 ① 自定义枚举类 ② enum关键字定义枚举类 ③ enum 枚举类的方法 ④ enum 枚举 ...

  4. java枚举类中字段有没有必要加final____枚举类字段 Field ‘xxx‘ may be ‘final‘

    java枚举类中字段有没有必要加final 今天在写一个系统统一返回码的枚举类时候,突然想到一个问题,当不小心手抖给枚举类自动生成了set方法,而恰巧在用的地方不小心用了set方法,从而修改了code ...

  5. JAVA 枚举类的初步理解

    JAVA 枚举类的初步理解 现在Java的枚举类在真实项目中已经用的比较频繁,比静态常量更好用,也更有限定性,enum类可以用来表示有限的类对象,比如星期.月份.性别或者项目中的产品类型 像诸如此类的 ...

  6. java 枚举类组合在一起_Java,.NET,但为什么在一起?

    java 枚举类组合在一起 十二年前,Sun微系统公司大张旗鼓地宣布了一种新的编程语言和环境,用于使网页更具动态性和"活力". 当然,现在,Java编程语言是一种无处不在的工具,它 ...

  7. java 枚举类型enum ppt,关于JAVA枚举类使用的异常

    当前位置:我的异常网» J2SE » 关于JAVA枚举类使用的异常 关于JAVA枚举类使用的异常 www.myexceptions.net  网友分享于:2013-01-24  浏览:5次 关于JAV ...

  8. Java枚举类使用要点

    Java枚举类 Java中的枚举类型定义使用enum关键字,定义时,系统默认继承Enum抽象类.先来看一下枚举类的使用. enum Sex {// 枚举对象必须要在第一行MAIL("男&qu ...

  9. Java枚举类的写法

    Java枚举类的写法 枚举也是一个类(枚举对象,属性,构造器,get方法),由于是枚举,一般我们只需要得到值,而不需要set值

最新文章

  1. 此代码募集最优秀的答案
  2. md5sum命令详解
  3. python循环函数怎么改变变量_python:循环定义多个变量
  4. MySQL的索引类型及简单优化
  5. 菜鸟学习C++练笔之整理搜狗2008版语料库--获取分类语料库
  6. spool命令、创建一个表,创建而且copy表,查看别的用户下的表,rowid行地址 索引的时候使用,表的增删改查,删除表,oracle的回收站...
  7. andriod studio获取root_怎样获得root权限
  8. 武汉大学计算机学院程序大赛,“星网锐捷杯”华中区高校研究生程序设计大赛通知...
  9. Windows系统重装Linux系统
  10. python中数字转英文_如何用Python实现阿拉伯数字转换英文数字 python3 将中文句子中汉字数字转阿拉伯数字...
  11. Eclipse插件(RCP)自定义透视图
  12. 苹果6s最大屏幕尺寸_苹果 iPhone 12 Pro DXOMARK 屏幕评分 87 分,最大问题是黄色色偏 - 苹果,iPhone...
  13. 10个值得珍藏的4K高清壁纸网站推荐
  14. android 自定义 对号,【Android】自定义progressBar和动画显示对号
  15. STM32的硬件I2C与AT24C16
  16. 2D横板动作游戏常用角色移动逻辑(转)
  17. 云锁 php一句话,关于php一句话免杀的分析转载
  18. w ndows7共享,七仔教你学Windows 7:玩转家庭网络共享
  19. 计算机毕业设计 SSM养老院管理系统 智慧养老院管理系统 养老院信息管理系统Java Vue MySQL数据库 远程调试 代码讲解
  20. C++版本OpenCv教程(六)namedWindow函数imshow函数的使用

热门文章

  1. C#语言 SqlClient接口SQL Sever数据库类+OleDb接口Access数据库类
  2. Deeply supervised salient object detection with short connections 论文复现
  3. 【6月比赛合集】103场可报名的数据挖掘大奖赛,任君挑选!
  4. 程序员如何提高生产效率?
  5. tesseract安装使用,人工智,图文识别验证码 系统操作(python)
  6. 服务器系统启用flash,windows无法启动flash helper service怎么办?_网站服务器运行维护,windows,flash helper service...
  7. html父级添加伪类after,关于伪类after后续追加,实现js事件(如点击事件)
  8. 一牛网:MTK芯片大全,MTK资料下载,MTK开发工具
  9. 计算机专业的研究热点,计算思维研究热点及趋势
  10. Java深克隆实现方法