前文
这次当我入职一家新公司的时候,编写代码发现,里面还在大量的使用public static final…这种语句来神马一些状态常量。
很多时候,虽然都能暂时完成一样的功能,但武功高低,一看便知。因此我加入之后,迅速全面引入枚举类型,并且指定枚举的使用规范、统一实现的接口。。。
什么是枚举类型
枚举类型是Java 5中新增特性的一部分,它是一种特殊的数据类型,之所以特殊是因为它既是一种类(class)类型却又比类类型多了些特殊的约束,但是这些约束的存在也造就了枚举类型的简洁性、安全性以及便捷性。
枚举类型的定义
这段代码,是在enum没引入之前:
public class DayDemo { public static final int MONDAY =1; public static final int TUESDAY=2; public static final int WEDNESDAY=3; public static final int THURSDAY=4; public static final int FRIDAY=5; public static final int SATURDAY=6; public static final int SUNDAY=7; }
上述的常量定义常量的方式称为int枚举模式,这样的定义方式并没有什么错,但它存在许多不足:
1.如在类型安全和使用方便性上并没有多少好处
2.如果存在定义int值相同的变量,混淆的几率还是很大的,编译器也不会提出任何警告
3.操作上,比如我要拿到所有的枚举值,或者根据枚举值拿到具体的名字等都非常的不方便因此这种方式在枚举出现后并不提倡,现在我们利用枚举类型来重新定义上述的常量,同时也感受一把枚举定义的方式,如下定义周一到周日的常量
//枚举类型,使用关键字enum public enum Day { MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY }
相当简洁,使用起来也是异常的方便(下面会着重讲解它的用法)。
枚举的真身
需要看真身,首先我们得看看编译后的.class文件。
/** * @author fangshixiang@vipkid.com.cn * @description * @date 2018-11-03 16:49 */ public enum DayEnum { MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY }
查看.class文件如下:
我们发现它和普通的class文件一样,还是会生成一个同名的.class文件。现在我们反编译看看.class文件的内容:
public final class DayEnum extends Enum<DayEnum> { //编译器为我们添加的静态的values()方法 public static DayEnum[] values() { return (DayEnum[])$VALUES.clone(); } //编译器为我们添加的静态的valueOf()方法,注意间接调用了Enum也类的valueOf方法 public static DayEnum valueOf(String s) { return (DayEnum)Enum.valueOf(com/fsx/run/enums/DayEnum, s); } //私有构造函数 只能由编译器来调用 private DayEnum(String enumName, int index) { super(enumName, index); } //前面定义的7种枚举实例 public static final DayEnum MONDAY; public static final DayEnum TUESDAY; public static final DayEnum WEDNESDAY; public static final DayEnum THURSDAY; public static final DayEnum FRIDAY; public static final DayEnum SATURDAY; public static final DayEnum SUNDAY; //装载所有实例的一个数组 private static final DayEnum $VALUES[]; //通过静态代码快实例这些多例 static { MONDAY = new DayEnum("MONDAY", 0); TUESDAY = new DayEnum("TUESDAY", 1); WEDNESDAY = new DayEnum("WEDNESDAY", 2); THURSDAY = new DayEnum("THURSDAY", 3); FRIDAY = new DayEnum("FRIDAY", 4); SATURDAY = new DayEnum("SATURDAY", 5); SUNDAY = new DayEnum("SUNDAY", 6); //都装载进去 $VALUES = (new DayEnum[] { MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY }); } }
看到了enum类型编译后的真身,很多结果都一目了然了有木有。
我们注意到,DayEnum类是final类型的,将无法被继承。而且该类继承自java.lang.Enum类(它是一个抽象类,所有的enum类型的类都是它的子类,提供很多方法和定义)
这里提醒大家一点,Enum类内部会有一个构造函数,该构造函数只能有编译器调用,我们是无法手动操作的
枚举的Class对象
需求:我们需要一次性获取到所有的枚举值对象:
public static void main(String[] args) { DayEnum[] values = DayEnum.values(); DayEnum[] enumConstants = DayEnum.class.getEnumConstants(); //判断某个class是否为枚举类型 System.out.println(MONDAY.getClass().isEnum()); //true }
enum中定义抽象方法
与常规抽象类一样,enum类允许我们为其定义抽象方法,然后使每个枚举实例都实现该方法,以便产生不同的行为方式,注意abstract关键字对于枚举类来说并不是必须的如下:
public enum EnumDemo3 { FIRST{ @Override public String getInfo() { return "FIRST TIME"; } }, SECOND{ @Override public String getInfo() { return "SECOND TIME"; } } ; /** * 定义抽象方法 * @return */ public abstract String getInfo(); //测试 public static void main(String[] args){ System.out.println("F:"+EnumDemo3.FIRST.getInfo()); System.out.println("S:"+EnumDemo3.SECOND.getInfo()); /** 输出结果: F:FIRST TIME S:SECOND TIME */ } }