当前位置: 首页 > 科技观察

为什么建议您使用枚举?

时间:2023-03-14 16:54:30 科技观察

本文转载自微信公众号“Java中文社区”,作者雷哥。转载本文请联系Java中文社区公众号。枚举是JDK1.5新增的一种数据类型。使用枚举,我们可以描述一些具体的业务场景,比如一年中的春、夏、秋、冬,每周的周一到周日。有各种颜色,可以用来描述一些状态信息,比如错误码等。枚举类型不仅存在于Java语言中,在其他语言中也可以找到,比如C#、Python等.,但是我发现在实际项目中很少有人用到枚举,所以这篇文章就讲一下枚举相关的内容,让小伙伴们对枚举有个大概的印象,让至少一类“枚举”编程的时候可以想到。本文结构如下:枚举的7种使用方式很多人不使用枚举的一个重要原因是对枚举不够熟悉,那么我们先从枚举的7种使用方式说起。用法一:常量在JDK1.5之前,我们将常量定义为publicstaticfinal...,但是有了枚举,我们可以将这些常量定义为一个枚举类。实现代码如下:publicenumColorEnum{RED,GREEN,BLANK,YELLOW}用法二:switch在switch判断中使用枚举,使代码更具可读性。实现代码如下:enumColorEnum{GREEN,YELLOW,RED}publicclassColorTest{ColorEnumcolor=ColorEnum.RED;publicvoidchange()break;caseGREEN:color=ColorEnum.YELLOW;break;}}}用法三:我们可以在枚举中添加方法在枚举中添加一些方法,使枚举具有更多的特性。实现代码如下:publicclassEnumTest{publicstaticvoidmain(String[]args){ErrorCodeEnumerrorCode=ErrorCodeEnum.SUCCESS;System.out.println("状态码:"+errorCode.code()+"状态信息:"+errorCode.msg());}}enumErrorCodeEnum{SUCCESS(1000,"success"),PARAM_ERROR(1001,"parametererror"),SYS_ERROR(1003,"systemerror"),NAMESPACE_NOT_FOUND(2001,"namespacenotfound"),NODE_NOT_EXIST(3002,"nodenotexist"),NODE_ALREADY_EXIST(3003,"nodealreadyexist"),UNKNOWN_ERROR(9999,"未知wnerror");privateintcode;privateStringmsg;ErrorCodeEnum(intcode,Stringmsg){this.code=code;this.msg=msg;}publicintcode(){returncode;}publicStringmsg(){returnmsg;}publicstaticErrorCodeEnumgetErrorCode(intcode){for(ErrorCodeEnumit):ErrorCodeEnum.values()){if(it.code()==code){returnit;}}returnUNKNOWN_ERROR;}}上面程序的执行结果为:Statuscode:1000状态信息:success用法4:覆盖枚举方法我们可以重写一些枚举方法来实现自己的业务,比如我们可以重写toString()方法,实现代码如下:.out.println(colorEnum.toString());}}enumColorEnum{RED("红色",1),GREEN("绿色",2),BLANK("白色",3),YELLOW("黄色",4);//成员变量privateStringname;privateintindex;//构造方法privateColorEnum(Stringname,intindex){this.name=name;this.index=index;}//覆盖方法@OverridepublicStringtoString(){returnthis.index+":"+this.name;}}上面程序的执行结果为:1:红色用法5:实现接口枚举类可以用来实现接口,但是不能用来继承类,因为枚举默认继承java.lang.Enum类,在Java中language允许有多个接口,但不能继承多个父类。实现代码如下:publicclassEnumTest{publicstaticvoidmain(String[]args){ColorEnumcolorEnum=ColorEnum.RED;colorEnum.print();System.out.println("Color:"+colorEnum.getInfo());}}interfaceBehaviour{voidprint();StringgetInfo();}enumColorEnumimplementsBehaviour{RED("Red",1),GREEN("Green",2),BLANK("White",3),YELLOW("Yellow",4);privateStringname;privateintindex;privateColorEnum(Stringname,intindex){this.name=name;this.index=index;}@Overridepublicvoidprint(){System.out.println(this.index+":"+this.name);}@OverridepublicStringgetInfo(){returnthis.name;}}上面程序的执行结果是:1:RedColor:RedUsage6:在接口中组织枚举类我们可以在一个接口中创建多个枚举类,可以用来实现“多态”,也就是说我们可以将具有相同特性但实现细微差别的枚举类集合到一个接口中,实现代码如下:publicclassEnumTest{publicstaticvoidmain(String[]args){//AssignthefirstenumerationclassColorInterfacecolorEnum=ColorInterface.ColorEnum.RED;System.out.println(colorEnum);//赋值第二个枚举类colorEnum=ColorInterface.NewColorEnum.NEW_RED;System.out.println(colorEnum);}}interfaceColorInterface{枚举颜色EnumimplementsColorInterface{GREEN,YELLOW,RED}enumNewColorEnumimplementsColorInterface{NEW_GREEN,NEW_YELLOW,NEW_RED}}上面程序的执行结果为:REDNEW_RED用法七:使用枚举集合在Java语言中,与枚举类相关的枚举集合有两个类java.可以使用util.EnumSet和java.util.EnumMap来实现更多的功能使用EnumSet可以保证元素不重复,并且可以获取到指定范围内的元素。示例代码如下:add(ColorEnum.RED);list.add(ColorEnum.RED);//重复元素list.add(ColorEnum.YELLOW);list.add(ColorEnum.GREEN);//去除重复数据EnumSetenumSet=EnumSet.copyOf(list);System.out.println("Deduplication:"+enumSet);//获取指定范围的枚举(获取所有失败状态)EnumSeterrorCodeEnums=EnumSet.range(ErrorCodeEnum.ERROR,ErrorCodeEnum.UNKNOWN_ERROR);System.out.println("所有失败状态:"+errorCodeEnums);}}enumColorEnum{RED("红色",1),GREEN("绿色",2),BLANK("白色",3),YELLOW("Yellow",4);privateStringname;privateintindex;privateColorEnum(Stringname,intindex){this.name=name;this.index=index;}}enumErrorCodeEnum{SUCCESS(1000,"success"),ERROR(2001,"parametererror"),SYS_ERROR(2002,"系统错误r"),NAMESPACE_NOT_FOUND(2003,"namespacenotfound"),NODE_NOT_EXIST(3002,"nodenotexist"),NODE_ALREADY_EXIST(3003,"nodealreadyexist"),UNKNOWN_ERROR(9999,"unknownerror");privateintcode;privateStringmsg;interrorCodegms({this.code=code;this.msg=msg;}publicintcode(){returncode;}publicStringmsg(){returnmsg;}}以上程序执行结果为:deduplication:[RED,GREEN,YELLOW]allfailurestatus:[ERROR,SYS_ERROR,NAMESPACE_NOT_FOUND,NODE_NOT_EXIST,NODE_ALREADY_EXIST,UNKNOWN_ERROR]EnumMap类似于HashMap,但它是专门为枚举设计的Map集合,与HashMap相比,它的性能更高,因为它内部摒弃了使用链表和red的结构黑树,使用数组作为数据存储的结构EnumMap的基本使用示例如下:importjava.util.EnumMap;publicclassEnumTest{publicstaticvoidmain(String[]args){EnumMapenumMap=newEnumMap<>(ColorEnum.class);enumMap.put(ColorEnum.RED,"red");enumMap.put(ColorEnum.GREEN,"绿色");enumMap.put(ColorEnum.BLANK,"White");enumMap.put(ColorEnum.YELLOW,"Yellow");System.out.println(ColorEnum.RED+":"+enumMap.get(ColorEnum.RED));}}enumColorEnum{RED,GREEN,BLANK,YELLOW;}以上程序的执行结果为:RED:使用红色的注意事项阿里《Java开发手册》关于枚举的相关规定如下,需要稍微注意一下使用时。【强制】所有枚举类型的字段都必须有注释,说明每个数据项的用途。【参考】枚举类名要以Enum为后缀,枚举成员名要全部大写,单词之间用下划线分隔。解释:枚举其实是一个特殊的常量类,构造函数默认强制为private。正例:枚举名称ProcessStatusEnum的成员名称:SUCCESS/UNKNOWN_REASON。如果在枚举没有诞生之前,也就是在JDK1.5版本之前,不使用枚举,我们通常使用int常量来表示枚举。实现代码如下:publicstaticfinalintCOLOR_RED=1;publicstaticfinalintCOLOR_BLUE=2;publicstaticfinalintCOLOR_GREEN=3;但是使用int类型可能会有两个问题:第一,int类型本身是不安全的。如果程序员在定义int时漏掉了一个final关键字,就会有被别人修改的风险。另一方面,枚举类,它“天生”是常量类,不存在被修改的风险(原因见后半部分);第二,使用int类型的语义不够清晰,比如我们只输出1...2..3这样的数字,我们肯定不知道是什么意思。然后有人说,那就用常量字符吧,这样就不知道语义了吧?实现示例代码如下:publicstaticfinalStringCOLOR_RED="RED";publicstaticfinalStringCOLOR_BLUE="BLUE";publicstaticfinalStringCOLOR_GREEN="GREEN";但是这也存在一个问题,一些初级程序员会不按套路去做。他们可能直接使用字符串的值进行比较,而不是直接使用枚举字段。实现示例代码如下:color)){System.out.println("Blue");}}}这样,当我们修改枚举中的值时,程序就爽了。枚举使用场景枚举常见的使用场景是单例,其完整的实现代码如下:publicclassSingleton{//枚举类型是线程安全的,只会加载一次privateenumSingletonEnum{INSTANCE;//声明单例对象privatefinalSingletoninstance;//实例化SingletonEnum(){instance=newSingleton();}privateSingletongetInstance(){returninstance;}}//获取实例(单例对象)publicstaticSingletongetInstance(){returnSingletonEnum.INSTANCE.getInstance();}privateSingleton(){}//类方法publicvoidsayHi(){System.out.println("Hi,Java.");}}classSingletonTest{publicstaticvoidmain(String[]args){Si??ngletonsingleton=Singleton.getInstance();singleton.sayHi();}}因为枚举只会在加载类的时候被加载一次,所以是线程安全的,这也是《Effective Java》的作者强烈推荐使用枚举来实现单例的主要原因。为什么知识扩展枚举是线程安全的?这从枚举最终生成的字节码开始。首先,让我们定义一个简单的枚举类:publicenumColorEnumTest{RED,GREEN,BLANK,YELLOW;}然后我们再将上面的那段代码编写为字节码,具体内容如下:publicfinalclassColorEnumTestextendsjava.lang.Enum{publicTfinalREDColor;publicstaticfinalColorEnumTestGREEN;publicstaticfinalColorEnumTestBLANK;publicstaticfinalColorEnumTestYELLOW;publicstaticColorEnumTest[]values();publicstaticColorEnumTestvalueOf(java.lang.String);static{};}从上面的结果可以看出,枚举类最终会被编译成final修饰的普通类,它的所有属性也会被static和final关键字修饰,所以枚举类将是项目启动时显示是由JVM加载和初始化的,这个执行过程是线程安全的,所以枚举类也是线程安全的类。Tips:代码反编译的过程是使用javac命令将java代码编译成字节码(.class),然后使用javap命令查看编译后的字节码。枚举比较技巧我们在枚举比较就可以的时候使用==,因为枚举类是在程序加载时创建的(不是new的),而枚举类不允许直接使用newoutside关键字创建枚举实例,所以我们在使用枚举类时本质上只有一个对象,所以在枚举比较时使用==就足够了。而当我们查看枚举equlas()的源码时,会发现其实里面直接调用了==方法。源码如下:publicfinalbooleanequals(Objectother){returnthis==other;}使用方式:常量、switch、向枚举中添加方法、重写枚举方法、实现接口、在接口中组织枚举类、使用枚举集合等等,然后说说如果不用枚举类就用int类型和String类型有一些缺点:语义不够清晰,容易被修改,有被修改的风险被误用,所以我们应该在合适的环境中尽量使用枚举类。并且我们也谈到了枚举类的使用场景——单例,以及为什么枚举类是安全的。最后说了枚举比较的小技巧。希望这篇文章对您有所帮助。评论与信用https://www.iteye.com/blog/softbeta-1185573链接:https://mp.weixin.qq.com/s/HDotguLpNgtwK-Jz2UsODQ