三分钟快速掌握Java中枚举(enum)
什么是枚举?
枚举是JDK5引入的新特性。在某些情况下,一个类的对象是固定的,就可以定义为枚举。在实际使用中,枚举类型也可以作为一种规范,保障程序参数安全。枚举有以下特点:
- Java中枚举和类、接口的级别相同。
- 枚举和类一样,都有自己的属性、方法、构造方法,不同点是:枚举的构造方法只能是private修饰,也就无法从外部构造对象。构造方法只在构造枚举值时调用。
- 使用enum关键字声明一个枚举类型时,就默认继承自Java中的java.lang.Enum类,并实现了java.lang.Seriablizable和java.lang.Comparable两个接口。
- 所有的枚举值都是publicstaticfinal的,且非抽象的枚举类不能再派生子类。
- 枚举类的所有实例(枚举值)必须在枚举类的第一行显式地列出,否则这个枚举类将永远不能产生实例。
- 判断枚举是否相同时,使用==和equals是一样的。
下面是java.lang.Enum类中的equals():
//这里是final修饰的,不允许子类重写 publicfinalbooleanequals(Objectother){ returnthis==other; }
枚举的常用方法
intcompareTo(Eo)
比较此枚举与指定对象的顺序。在该对象小于、等于或大于指定对象时,分别返回负整数、零或正整数。枚举常量只能与相同枚举类型的其他枚举常量进行比较。
//Enum中的源码 publicfinalintcompareTo(Eo){ Enumother=(Enum)o; Enumself=this; if(self.getClass()!=other.getClass()&&//optimization self.getDeclaringClass()!=other.getDeclaringClass()) thrownewClassCastException(); returnself.ordinal-other.ordinal; }
Stringname()
返回此枚举实例的名称。
staticvalues()
返回一个包含全部枚举值的数组,可以用来遍历所有枚举值。
StringtoString()
返回此枚举实例的名称,即枚举值。与name()一样。
//Enum中name()和toString() publicStringtoString(){ returnname; } publicfinalStringname(){ returnname; }
intordinal()
返回枚举值在枚举类中的索引值(从0开始),即枚举值在枚举声明中的顺序,这个顺序根据枚举值声明的顺序而定。
<TextendsEnum<T>>valueOf()
返回带指定名称的指定枚举类型的枚举常量,名称必须与在此类型中声明枚举常量所用的标识符完全匹配(不允许使用额外的空白字符)。这个方法与toString相对应,因此重写toString()方法,一定要重写valueOf()方法(我们可以重写toString()方法,但不能自己重写valueOf()方法,当我们重写toString()方法时,valueOf()方法会自动重写,不用我们理会。)
枚举的应用
枚举是一种特殊的类型,其用法和普通的类使用非常相似。
代替一组常量
publicenumColor{ RED,GREEN,BLANK,YELLOW }
switch语句中使用
//JDK1.6中switch加入了对枚举的支持 enumSignal{ GREEN,YELLOW,RED } ... switch(color){ caseRED: color=Signal.GREEN; break; } ...
向枚举中添加方法
publicenumColor{ RED("红色"),GREEN("绿色"),BLANK("白色"),YELLO("黄色"); //成员变量 privateStringname; //构造方法 privateColor(Stringname){ this.name=name; } //getset方法 publicStringgetName(){ returnname; } publicvoidsetName(Stringname){ this.name=name; } }
实现接口
publicinterfaceBehaviour{ voidprint(); } publicenumColorimplementsBehaviour{ RED("红色",1),GREEN("绿色",2),BLANK("白色",3),YELLO("黄色",4); //接口方法 @Override publicvoidprint(){ System.out.println(this.index+":"+this.name); } }
包含抽象方法的枚举类
publicenumOperation{ //用于执行加法运算 PLUS{//花括号部分其实是一个匿名内部子类 @Override publicdoublecalculate(doublex,doubley){ returnx+y; } }, //用于执行减法运算 MINUS{//花括号部分其实是一个匿名内部子类 @Override publicdoublecalculate(doublex,doubley){ //TODOAuto-generatedmethodstub returnx-y; } }, //用于执行乘法运算 TIMES{//花括号部分其实是一个匿名内部子类 @Override publicdoublecalculate(doublex,doubley){ returnx*y; } }, //用于执行除法运算 DIVIDE{//花括号部分其实是一个匿名内部子类 @Override publicdoublecalculate(doublex,doubley){ returnx/y; } }; //为该枚举类定义一个抽象方法,枚举类中所有的枚举值都必须实现这个方法 publicabstractdoublecalculate(doublex,doubley); }
使用枚举实现单例(单例的最佳实践)
好处:
1.利用的枚举的特性实现单例
2.由JVM保证线程安全
3.序列化和反射攻击已经被枚举解决
publicenumSingleton{ INSTANCE; publicSingletongetInstance(){ //增加这个方法是让别人明白怎么使用,因为这种实现方式还比较少见。 returnINSTANCE; } }
其他关于枚举的使用
EnumSet
range(Efrom,Eto)
从枚举值中获取一段范围的Set。
for(WeekDayEnumday:EnumSet.range(WeekDayEnum.Mon,WeekDayEnum.Fri)){ System.out.println(day); }
of(Efirst,E...rest)
创建一个最初包含指定元素的枚举Set。
noneOf(Class<E>elementType)
创建一个具有指定元素类型的空枚举Set。
EnumMap
EnumMap(Class<K>keyType)
创建一个具有指定键类型的空枚举Map。
Map<Weather,String>enumMap=newEnumMap<Weather,String>(Weather.class); enumMap.put(Weather.Sunny,"晴天"); enumMap.put(Weather.Rainy,"雨天");
Android中的枚举
Enum需要占用较大的内存,如果对内存敏感,请尽量少使用Enum,换成静态常量。
但是如果不使用枚举,会出现一些安全隐患,所以官方推出了两个注解,可以在编译时期进行类型检查,以此替代枚举。这两个注解分别是:@IntDef和@StringDef。位于compile'com.android.support:support-annotations:+'。
使用示例
@StringDef的使用与@IntDef一致,这里以@IntDef为例。
publicinterfaceQRCodeType{ intWECHAT=0; intALIPAY=1; @IntDef({WECHAT,ALIPAY}) @Retention(RetentionPolicy.SOURCE) @Target({ElementType.FIELD,ElementType.METHOD,ElementType.PARAMETER}) @interfaceChecker{ } } publicclassQRCode{ @QRCodeType.Checker//定义在属性 privateinttype; publicvoidsetType(@QRCodeType.Checkerinttype){//定义在参数 this.type=type; } @QRCodeType.Checker//定义在方法(也就是检查返回值的类型) publicintgetType(){ returntype; } }
使用建议
开发中使用范围最广的就是利用枚举代替一组静态常量,这种情况可以使用以上注解方式替代。
当枚举还含有其它功能时(如:包含其它定义的方法),则不能替换。
总结
以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作能带来一定的帮助,如果有疑问大家可以留言交流。