Java中枚举类的深入理解
概述
在此之前由于个人在学习和开发中对枚举类的应用较少,所以对枚举类的知识点并没进行深入的了解,但最近写代码中突然想到了枚举类,抱着完善自身的知识的目的,就较为深入的了解了Java中的枚举类。
我在学习任何东西之前都会大致弄清楚这个东西存在的目的是什么,这样才能更加深入的理解一些东西。同样的,在学习枚举类之前,我们也需要摸清楚Java5才出来的枚举类到底有什么作用。
为什么会出现枚举类
这里我们给出一种场景,给出一个Employee类,该类需要定义一个字段保存这个员工休息日(周一到周日的一天),那我们如何表示呢?
有人可能就说了直接定义成int型不就行了,1表示星期一.....。代码也就是这样的:
public class Employee {
private String name;
private int playday;
public Employee(String name, int playday) {
super();
this.name = name;
this.playday = playday;
}
}
但是问题来了,使用这个类的用户怎么知道传进去的数字代表的是什么,更危险的是用户可以传入一个负数,这显然就不符合要求了。可能有些人就会说了,在方法上面写一个注释不就行了,但是这么做明显是把命运交给了别人,万一别人就是不按规定来呢?
我们来对程序做第一版改进:
public class Employee {
public static final int Mon=1;
public static final int Tues=2;
public static final int Wed=3;
public static final int Thur=4;
public static final int Fri=5;
public static final int Sat=6;
public static final int Sun=7;
private String name;
private int playday;
public Employee(String name, int playday) {
super();
this.name = name;
this.playday = playday;
}
}
这样我们每次在创建Employee对象过程中传入int类型值时就不需要手动指定一个常量值了,只需要使用Employee中定义的静态常量即可。就像这样:
Employee employee = new Employee("zhangsan", Employee.Fri);
但是这么做并没有完全解决上面所说的问题,用户还是可以手动指定指定一个整数类型的值。看来我们还需要对程序进行改进:
第二版改进:我们需要重新定义一个类来表示星期了!
public class WeekDay {
public static final WeekDay Mon=new WeekDay(1, "Mon");
public static final WeekDay Tues=new WeekDay(2, "Tues");
public static final WeekDay Wed=new WeekDay(3, "Wed");
public static final WeekDay Thur=new WeekDay(4, "Thur");
public static final WeekDay Fri=new WeekDay(5, "Fri");
public static final WeekDay Sat=new WeekDay(6, "Sat");
public static final WeekDay Sun=new WeekDay(7, "Sun");
private int day;
private String info;
//构造器被私有化
private WeekDay(int day, String info) {
super();
this.day = day;
this.info = info;
}
}
此时Employee类需要进行相应的改进
public class Employee {
private String name;
private WeekDay playday;
public Employee(String name, WeekDay playday) {
super();
this.name = name;
this.playday = playday;
}
}
经过两次改进程序得到了完善,由于WeekDay类的构造器被私有化(别和我杠可以通过反射等手段获得新的WeekDay对象),所以用户在创建Employee对象时只能使用WeekDay中的静态常量了,所以最初的那些问题也就解决了。
但是!!!!!!!!
你没觉得这么写太麻烦了吗?为了Employee类中的一个属性,需要重新建一个表示常量的类,并且代码还比较多,此时Java5出来的特性——枚举类就可以简单的解决这个问题了。
引入枚举类
Java 5新增了一个enum关键字(表面上看它与class interface地位相同),用于定义枚举类。
我们通过枚举类对第二次改版的代码进行改造:
定义枚举类:
public enum WeekDayEnum {
Mon,Tues,Wed,Thu,Fri,Sat,Sun;
}
改造Employee类:
public class Employee {
private String name;
private WeekDayEnum playday;
public Employee(String name, WeekDayEnum playday) {
super();
this.name = name;
this.playday = playday;
}
}
创建Employee对象:
Employee lisi = new Employee("lisi", WeekDayEnum.Mon);
这么写代码是不是发现简单了很多,文化人要说“优雅”这个词,哈哈。
那我们就来说说Java中的枚举类的语法规则:
1. 枚举类的所有的常量(或者说是枚举类的实例)必须在第一行中列出来,常量与常量之间用逗号隔开,列出来的常量系统会自动加上 public static final修饰符,不需要程序员手动添加。
2. 枚举类可以实现一个或多个接口。
3. 枚举类的构造器只能用只能使用private修饰,不然会报错,如果省略修饰符那么系统会默认加上private。
4. 枚举类底层继承至Enum类,所以枚举类不可继承其它类。
5. 枚举类底层由final修饰,所以它不可被其它类继承。
6. 枚举类可以拥有静态和非静态方法。
你以为说完枚举类的语法,枚举类就学完了??
哪有这么简单。。。。
深入理解枚举类
我们将WeekDayEnum类通过XJad反编译工具进行反编译,反编译的结果如下:
public final class WeekDayEnum extends Enum
{
public static final WeekDayEnum Mon;
public static final WeekDayEnum Tues;
public static final WeekDayEnum Wed;
public static final WeekDayEnum Thu;
public static final WeekDayEnum Fri;
public static final WeekDayEnum Sat;
public static final WeekDayEnum Sun;
private static final WeekDayEnum ENUM$VALUES[];
private WeekDayEnum(String s, int i)
{
super(s, i);
}
public static WeekDayEnum[] values()
{
WeekDayEnum aweekdayenum[];
int i;
WeekDayEnum aweekdayenum1[];
System.arraycopy(aweekdayenum = ENUM$VALUES, 0, aweekdayenum1 = new WeekDayEnum[i = aweekdayenum.length], 0, i);
return aweekdayenum1;
}
public static WeekDayEnum valueOf(String s)
{
return (WeekDayEnum)Enum.valueOf(cn/tjd/enumtest/WeekDayEnum, s);
}
static
{
Mon = new WeekDayEnum("Mon", 0);
Tues = new WeekDayEnum("Tues", 1);
Wed = new WeekDayEnum("Wed", 2);
Thu = new WeekDayEnum("Thu", 3);
Fri = new WeekDayEnum("Fri", 4);
Sat = new WeekDayEnum("Sat", 5);
Sun = new WeekDayEnum("Sun", 6);
ENUM$VALUES = (new WeekDayEnum[] {
Mon, Tues, Wed, Thu, Fri, Sat, Sun
});
}
}
哇,你会发现这个类和我们当初写的WeekDay类怎么很相似呢?
反编译后的关注点:
1. 枚举类默认继承java.lang.Enum类,而不是传统类的Object父类。
2. 类名用final修饰,也就是说枚举类不能有子类继承它。
3. 构造器是私有的。
细细体会反编译的源码。。。。。
枚举类的其他用法
这里我值提供一些思路:
1. 枚举类可以用于做常量,也就是我们上面所描述的。
2. 枚举类可以写单例模式,并且可以防止通过反射或序列化进行单例攻击。
参考这篇文章:https://www.cnblogs.com/chiclee/p/9097772.html
3. 可以用在switch语句中做分支判断。。
等.....
原创不易啊!!走过路过不要错过,帮博主点个赞吧,嘻嘻!!