一. 枚举(enumeration)的引入和模拟
需求: 定义一个Employee(员工),使用一个变量restday来表示他哪一天休息(一周的哪一天)。
class Employee{
private int restday;
public void setRestday(int restday)
{
this.restday = restday;
}
public int getRestday()
{
return restday;
}
}
class EnumerationDemo
{
public static void main(String[] args)
{
Employee employee = new Employee();
employee.setRestday(13);
}
}
上述使用int类型来表示星期几存在的问题:
(1):类型不安全,完全可以设置非[1,7]之间的数。
(2):业务含义不够明确,设置1表示周几?周一/周日?
解决方案:专门使用一个类Weekday来表示周一到周日,使用7个常量来表示。
class Weekday
{
// Monday、Tuesday、Wednesday、Thursday、Friday、Saturday、Sunday
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;
}
此时,业务含义很明确,因为Weekday.WEDNESDAY就表示周三的意思。
但是, 因为在Employee中的restday的类型是int类型,我们依然可以随意设置int类型的数据。所以,还是没有解决数据类型不安全的问题。
因为int类型不安全,我们把休息日使用一个对象类型来表示,并固定该休息日的值只能是周一到周日。
class Weekday
{
// Monday、Tuesday、Wednesday、Thursday、Friday、Saturday、Sunday
private Weekday(){}; // 私有化构造器
public static final Weekday Monday = new Weekday();
public static final Weekday Tuesday = new Weekday();
public static final Weekday Wednesday = new Weekday();
public static final Weekday Thursday = new Weekday();
public static final Weekday Friday = new Weekday();
public static final Weekday Saturday = new Weekday();
public static final Weekday Sunday = new Weekday();
}
class Employee{
private Weekday restday;
public void setRestday(Weekday restday)
{
this.restday = restday;
}
public Weekday getRestday()
{
return restday;
}
}
class EnumerationDemo
{
public static void main(String[] args)
{
Employee employee = new Employee();
employee.setRestday(Weekday.Saturday);
Weekday restday = employee.getRestday();
if (restday == Weekday.Saturday || restday == Weekday.Sunday)
{
System.out.println("不上班,休息!");
return;
}
System.out.println("工作....");
}
}
二. 枚举的定义
枚举是从java5开始提供的一种新的数据类型,是一个特殊的类,就是固定的多个常量对象的集合。简单来说,枚举就是一个特殊的类。
枚举主要用来表示事物固定的类型。(后面慢慢学)
定义格式:
enmu 类名
{
常量A, 常量B, 常量C;
}
如:
enum Weekday
{
Monday,Tuesday,Wednesday,Thursday,Friday,Saturday,Sunday;
}
反编译:
等价于:
class Weekday
{
// Monday、Tuesday、Wednesday、Thursday、Friday、Saturday、Sunday
private Weekday(){}; // 私有化构造器
public static final Weekday MONDAY = new Weekday();
public static final Weekday TUESDAY = new Weekday();
public static final Weekday WEDNESDAY = new Weekday();
public static final Weekday THURSDAY = new Weekday();
public static final Weekday FRIDAY = new Weekday();
public static final Weekday SATURDAY = new Weekday();
public static final Weekday SUNDAY = new Weekday();
}
三. 枚举的特点
【这样写没有任何意义,每一个特点都是通过具体的原因引入的,不是在这里写总结】
(1) 枚举的直接父类,java.lang.enum,但是不能显示集成enum;
(2) 枚举就相当于一个类,可以定义构造方法、成员变量、普通方法、抽象方法等。
(3) 默认私有构造方法,即使不写访问权限也是private(是一个假的构造器,底层没有无参构造器)
(4) 每个实例分别用一个全局常量表示,枚举类的对象是固定的,实例个数有限(不能再增加),不能使用new关键字。
(5) 枚举实例必须位于枚举类型中的第一行,枚举实例表最后要有分号与其他成员分割。
(6) 枚举实例后有花括号时,该实例是枚举类型的匿名内部类对象(查看编译后的class文件)
四. 枚举的使用
(1)枚举中都是全局公共的静态常量,可以直接使用枚举名调用。
Weekday day = Weekday.SATURDAY;
(2)因为java.lang.Enum类是所有枚举类的父类,所以所有的枚举对象可以调用Enum类中的方法。
String name = 枚举对象.name(); //返回枚举对象的常量名称.
int ordinal = 枚举对象.ordinal(); //返回枚举对象的序号,从0开始.
String str = 枚举对象.toString(); //返回枚举对象的常量名称
如:
System.out.println(Weekday.FRIDAY .name());
System.out.println(Weekday.FRIDAY .ordinal());
System.out.println(Weekday.FRIDAY .toString());
---------- 运行java ----------
Friday
4
Friday
输出完成 (耗时 0 秒) - 正常终止
(3)编译器生成的枚举类的静态方法:枚举类型[] values();
Weekday[] values = Weekday.values();//返回当前枚举类型所有的常量,用一个数组封装起来
for(Weekday w : values){
System.out.println(w);
}
---------- 运行java ----------
Monday
Tuesday
Wednesday
Thursday
Friday
Saturday
Sunday
输出完成 (耗时 0 秒) - 正常终止
枚举类型 valueOf(String name);
Weekday day = Weekday.valueOf("MONDAY");//把一个指定名称字符串转换为当前枚举类中同名的常量
这个使用场景:一般前端传递数据到后端时,经常使用String类型,可以通过valueOf将String类型的数量转为枚举类型。
(4)从jave5开始出现枚举,switch也支持操作枚举类型。
switch只支持int类型,支持枚举是因为底层使用的枚举对象的ordinal;
而ordinal的类型依然是int类型
switch(Weekday.FRIDAY)
{
case MONDAY : break;
case TUESDAY : break;
case WEDNESDAY : break;
}
反编译:
补充:枚举的单例模式:
在《effective java》书中提到,建议使用枚举类做单例模式,这样很安全,即使使用反射也不能创建对象。
我们先看一下之前写的单例模式:
class ArrayUtil
{
// (1) 必须在该类中,自己先new一个对象;
private static final ArrayUtil instance = new ArrayUtil();
// (2) 私有化构造器;
private ArrayUtil(){}
// (3) 向外暴露一个公共的静态方法用于获取自身的对象
public static ArrayUtil getInstance(){
return instance;
}
// 相关工具方法操作
public void sort(int[] arr){
// 排序
}
}
使用枚举:
// 枚举写法
enum ArrayUtil
{
INSTANCE;
// 相关工具方法操作
public void sort(int[] arr){
// 排序操作
}
}
class SingletonDemo
{
public static void main(String[] args)
{
System.out.println(ArrayUtil.INSTANCE);// 每次获取到的单例都是相同的
System.out.println(ArrayUtil.INSTANCE);
}
}