本文转载自微信公众号《程序新视野》,作者为二哥。转载本文请联系程序新视界公众号。Java枚举,也称为Java枚举类型,是一种其字段由一组固定常量组成的类型。枚举的主要目的是强制执行编译时类型安全。enum关键字是Java中的保留关键字。在编译或设计时,当我们知道所有变量的可能性时,尽量使用枚举类型。本文将使您全面系统地了解枚举的使用以及您会遇到的一些问题。Java中的枚举枚举通常是相关常量的集合。其他编程语言早就使用枚举了,比如C++。从JDK1.5开始,Java也开始支持枚举类型。枚举是一种特殊的数据类型。它不仅是类类型,而且比类类型有一些特殊的约束。这些约束也有助于枚举类型的简单性、安全性和便利性。在Java中,枚举类型是通过enum声明的,默认继承自java.lang.Enum。因此,在声明一个枚举类时,它不能继承其他类。枚举声明在生活中,我们经常会标识方向,东、西、北、南,它们的名称、属性等基本确定了,我们可以将其声明为枚举类型:publicenumDirection{EAST,WEST,NORTH,SOUTH;}同样,一周七天也可以声明为枚举类型:enumDay{MONDAY,TUESDAY,WEDNESDAY,THURSDAY,FRIDAY,SATURDAY,SUNDAY}在没有枚举或者没有枚举的情况下,并不代表不能定义变量,我们可以通过类或接口来定义常量:publicclassDay{publicstaticfinalintMONDAY=1;publicstaticfinalintTUESDAY=2;publicstaticfinalintWEDNESDAY=3;publicstaticfinalintTHURSDAY=4;publicstaticfinalintFRIDAY=5;publicstaticfinalintSATURDAY=6;publicstaticfinalintSUNDAY=7安全易用。如果有定义相同int值的变量,混淆的几率还是很高的,编译器不会发出任何警告。所以在可以使用枚举的情况下,不提倡这种写法。枚举的底层实现上面我们已经说过,枚举是一个特殊的类,每一个枚举项本质上都是枚举类本身的一个实例。因此,上面的枚举类Direction可以用下面的代码来举例说明:然后用javap命令查看对应class文件的内容:choupangxia.枚举(java.valueenums.Directionlang.String);static{};}可以看出,一个枚举被编译器编译后,变成了一个抽象类,它继承了java.lang.Enum;而枚举中定义的枚举常量,则成为对应的publicstaticfinal属性,其类型为抽象类的类型,其名称为枚举常量的名称。枚举使用示例通过上面的反编译我们可以看出,枚举选项本质上是publicstaticfinal变量,所以直接当做这样的变量使用即可。publicclassEnumExample{publicstaticvoidmain(String[]args){Directionnorth=Direction.NORTH;System.out.println(north);//PrintsNORTH}}枚举的ordinal()方法ordinal()方法用于获取枚举变量在枚举类中声明的顺序,下标是从0开始的,这和数组中的下标很相似。它设计用于复杂的基于枚举的数据结构,例如EumSet和EnumMap。Direction.EAST.ordinal();//0Direction.NORTH.ordinal();//2需要注意的是,如果枚举项声明的位置发生变化,那么ordinal方法的值也会随之变化。所以,进来避免这种方法。否则,当枚举项很多的时候,别人在中间增加或删除了一个项,会导致后面所有的顺序变化。枚举的values()和valueOf()values()方法可以获取枚举类中的所有变量,并以数组形式返回:Direction[]directions=Direction.values();for(Directiond:directions){System.out.println(d);}//Output:EASTWESTNORTHSOUTHvalues()方法是编译器插入到枚举类中的静态方法,但在其父类Enum中不存在该方法。valueOf(Stringname)方法类似于Enum类中的valueOf方法。它根据名称获取枚举变量。也是编译器生成的,但是更加简洁,只需要传递一个参数。Directioneast=Direction.valueOf("EAST");System.out.println(east);//输出:EAST枚举命名约定按照约定,枚举是常量,所以全部使用大写字母,样式为下划线分隔(UPPER_CASE)。即枚举类名与普通类约定相同,枚举中的变量与静态变量的命名约定一致。枚举构造方法枚举类默认不需要构造方法,默认变量是声明时的字符串。当然你也可以通过自定义构造函数来初始化枚举的一些状态信息。通常我们会在构造参数中传入两个参数,比如编码和描述。以上述方向为例:publicenumDirection{//enumfieldsEAST(0),WEST(180),NORTH(90),SOUTH(270);//constructorprivateDirection(finalintangle){this.angle=angle;}//internalstateprivateintangle;publicintgetAngle(){returnangle;}}如果我们想访问每个方向的角度,可以通过一个简单的方法调用:Directionnorth=Direction.NORTH;System.out.println(north);//NORTHSystem.out.println(north.getAngle());//90System.out.println(Direction.NORTH.getAngle());//90枚举中的方法枚举是一个特殊的类,所以它也可以像普通类一样有方法和属性。枚举中不仅可以声明具体方法,还可以声明抽象方法。方法访问权限可以是私有的、受保护的和公共的。你可以通过这些方法返回枚举项的值,也可以做一些内部的私有处理。publicenumDirection{//enumfieldsEAST,WEST,NORTH,SOUTH;protectedStringprintDirection(){Stringmessage="Youaremovingin"+this+"direction";System.out.println(message);returnmessage;}}对应的方法使用如下:Direction。NORTH.printDirection();Direction.EAST.printDirection();也可以在枚举类中定义抽象方法,但必须在每个枚举项中实现相应的抽象方法:publicenumDirection{//enumfieldsEAST{@OverridepublicStringprintDirection(){Stringmessage="Youaremovingineast.Youwillfacesunineveningtime.";returnmessage;}},WEST{@OverridepublicStringprintDirection(){Stringmessage="Youaremovinginwest.Youwillfacesunineveningtime.";returnmessage;}},NORTH{@OverridepublicStringprintDirection(){Stringmessage=;Youaremovinginnorth.Youwillfaceheadindaytime.";returnmessage;}},SOUTH{@OverridepublicStringprintDirection(){Stringmessage="Youaremovinginsouth.Seaahead.";returnmessage;}};publicabstractStringprintDirection();}抽象方法d调用,与普通方法相同:Ddirection.NORTH.printDirection();Direction.EAST.printDirection();通过这种方式,您可以轻松地为每个枚举实例定义不同的行为。比如需要打印每个枚举项的方向名称,就可以定义这样一个抽象方法。上面这个枚举类的例子,似乎表现出了多态的特点,但遗憾的是,枚举类型的实例毕竟不能作为类型传递。以下方法编译器无法通过://无法编译,Direction.NORTH是一个实例对象publicvoidtext(Direction.NORTHinstance){}枚举的继承上面已经提到枚举继承自java.lang.Enum,而Enum是一个抽象类:publicabstractclassEnum
