Java枚举类使用场景及实例解析
为什么要用枚举类
什么场景会用到枚举,比如在表示一周的某一天,一年中的四季,这样一组常量的时候我们会用到枚举。在Java引入枚举类之前常用一组int常量来表示枚举,这种方式称为int枚举模式(intenumpattern)。
privatestaticfinalintMONDAY=1;
privatestaticfinalintTUESDAY=2;
privatestaticfinalintWEDNESDAY=3;
privatestaticfinalintTHURSDAY=4;privatestaticfinalintCODE_START=1;
privatestaticfinalintCODE_STATUS=2;
privatestaticfinalintCODE_STOP=3;
这种我们非常习惯的模式其实存在着很多不足和问题,
- int枚举组不具备命名空间的能力,当表示具有相同命名常量时,需要添加前缀避免冲突
- int表示的枚举值不具有描述性,需要遍历判断具体的值并添加描述
- int枚举模式不具有安全性,此外int类型是编译时常量,如果与int枚举常量关联的值发生变化,必须重新编译,不重新编译虽然不影响运行,但是准确性已经不能保证
即便是升级为用String来表示枚举值,String枚举模式(Stringenumpattern),但这样同样存在其他问题,
初学者容易直接把字符串常量硬编码到代码中,不使用对应的常量字段(filed)名,一旦书写错误,编译器无法检查,但在运行时会报出异常
String枚举模式会存在一定的性能问题,涉及到字符串的比较操作
因此Java引入了枚举类型解决int和String枚举模式带来的诸多不足,枚举类型保证了编译时的类型安全,枚举类型有自己独立的命名空间,枚举类型便于扩展,可以添加方法和域实现其他的外部接口。
如何使用枚举类
创建枚举类
Java中枚举是一种特殊的引用类型,是类(Class)的一种,JDK1.5中开始引入枚举类型,在Java中使用enum关键字来声明枚举类,枚举类编译后默认继承了java.lang.Enum,因此枚举类不能在继承其他类,枚举一般用来声明某一特定类型的有穷集合,如用枚举表示四季
publicenumSeason{ SPRING,SUMMER,FALL,WINTER }
枚举类API
参考JDKapi1.8.CHM,可以看到枚举类的常用api如下:
namepublicfinalStringname()
返回此枚举常量的名称,与其枚举声明中声明的完全相同。大多数程序员应该使用toString()方法,因为toString方法可能会返回一个更加用户友好的名称。该方法主要用于专门的情况,其中正确性取决于获得确切的名称,这从发布到发布不会有所不同。
ordinalpublicfinalintordinal()
返回此枚举常数的序数(其枚举声明中的位置,其中初始常数的序数为零)。大多数程序员将不会使用这种方法。它被设计为使用复杂的基于枚举的数据结构,如EnumSet和EnumMap。
toStringpublicStringtoString()
返回声明中包含的此枚举常量的名称。该方法可以被覆盖,尽管它通常不是必需或不可取的。当一个更“程序员友好”的字符串形式存在时,枚举类型应该覆盖此方法。
重写:toString在Object
compareTopublicfinalintcompareTo(Eo)
将此枚举与指定的对象进行比较以进行订购。返回一个负整数,零或正整数,因为该对象小于,等于或大于指定对象。枚举常数仅与相同枚举类型的其他枚举常量相当。该方法实现的自然顺序是声明常量的顺序。
Specifiedby:compareTo在界面Comparable
参数:o-要比较的对象。
结果:负整数,零或正整数,因为该对象小于,等于或大于指定对象。
getDeclaringClasspublicfinalClass
返回与此枚举常量的枚举类型相对应的Class对象。当且仅当e1.getDeclaringClass()==e2.getDeclaringClass())时,两个枚举常量e1和e2具有相同的枚举类型。(此方法返回的值可能与使用常量特定类体的枚举常数Object.getClass()方法返回的值不同)
结果:该类对象对应于此枚举常量的枚举类型
valueOfpublicstatic
返回具有指定名称的指定枚举类型的枚举常量。该名称必须与用于声明此类型的枚举常量的标识符完全一致。(不允许使用外来空白字符。)
请注意,对于特定枚举类型T,可以使用该枚举上隐式声明的publicstaticTvalueOf(String)方法,而不是使用此方法将名称映射到
相应的枚举常量。枚举类型的所有常量可以通过调用该类型的隐式publicstaticT[]values()方法来获得。
values
此方法并未在API中提供,返回枚举类型所有对象实例,返回值枚举类型的数组。
枚举应用案例
上面简单描述了如何声明一个枚举类,这里结合实际应用场景描述枚举的其他用法
单例设计模式
说到单例模式很多人会比较熟悉懒汉、饿汉等常见的单例书写模式,用枚举表示枚举还是比较少见的,对于单例设计模式的多种写法,单元素的枚举类型已经成为实现Singleton的最佳方法。首先回顾下单例设计模式要求满足的特点:
- 构造方法私有化;
- 实例化的变量引用私有化;
- 获取实例的方法共有。
publicenumSingleton{ INSTANCE; publicSingletongetInstance(){ returnINSTANCE; } }
使用枚举方式创建单例的好处:
- 避免反射攻击
- 避免序列化问题
有穷对象集合
枚举类型中的构造器默认私有化,只能添加private修饰或者不添加
枚举类型中定义的抽象方法必须被所有常量中的具体方法所覆盖,特定于常量的方法实现可以结合特定于常量的数据结合起来
用枚举表示加减乘除的操作
publicenumOperation{ PLUS("+","加法"){ publicdoubleapply(doublex,doubley){ returnx+y; } }, MINUS("-","减法"){ publicdoubleapply(doublex,doubley){ returnx-y; } }, TIMES("*","乘法"){ publicdoubleapply(doublex,doubley){ returnx*y; } }, DIVIDE("/","除法"){ publicdoubleapply(doublex,doubley){ returnx/y; } }; privatefinalStringsymbol; privatefinalStringoperName; publicStringgetSymbol(){ returnsymbol; } publicStringgetOperName(){ returnoperName; } Operation(Stringsymbol,StringoperName){ this.symbol=symbol; this.operName=operName; } publicabstractdoubleapply(doublex,doubley); }
调用枚举中的方法
publicclassTestOpera{ publicstaticvoidmain(String[]args){ doublex=1; doubley=1; for(Operationoperate:Operation.values()){ System.out.println( operate.getOperName()+":"+x+operate.getSymbol()+y+"="+operate.apply(x,y) ); } } }
输出结果
加法:1.0+1.0=2.0
减法:1.0-1.0=0.0
乘法:1.0*1.0=1.0
除法:1.0/1.0=1.0
引入枚举类型,不仅可以描述枚举本身,还可以添加描述性字符串,甚至给每个对象添加结合特有常量的行为,也不用考虑其他安全性为题。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持毛票票。