枚举类型 enum
枚举类型是java 5 的新特性,即 enum 关键字,它使我们在需要群组并使用枚举类型集时,可以很方便的处理.在此之前,你需要创建一个整型常量集,必须要了解很多细节并需要格外仔细,以正确的产生enum的效果.
1. 在java 5 以前如何创建一个常量类来表示星期,代码如下
//表示雇员哪一天休息的类
public class Employee{
private int restDay;//表示休息日
public int getRestDay() {
return restDay;
}
public void setRestDay(int restDay) {
this.restDay = restDay;
}
}
//测试代码如下:
public static void main(String[] args) {
Employee e = new Employee();
e.setRestDay(2);
int restDay = e.getRestDay();
if (restDay == 6 || restDay == 7){
System.out.println("周末休息");
} else {
System.out.println("周一到周五休息");
}
}
//输出结果:
周一到周五休息
以上代码存在的问题:
用 int 类型做星期几存在的问题如下:
1. 类型不安全,完全可以设置 非 (1 - 7)之间的数字
2. 业务含义不明确,设置的 1 表示周几?
2. 解决方案,使用七个常量来表示星期几的常量类,代码如下:
//表示星期几的常量类
public class Weekday {
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();
}
//员工周几休息
public class Employee{
private Weekday restDay;//表示休息日
public Weekday getRestDay() {
return restDay;
}
public void setRestDay(Weekday restDay) {
this.restDay = restDay;
}
}
//测试方法
public static void main(String[] args) {
Employee e = new Employee();
e.setRestDay(Weekday.SATURDAY);
Weekday restDay = e.getRestDay();
if (restDay == Weekday.SATURDAY || restDay == Weekday.SUNDAY){
System.out.println("周末休息");
} else {
System.out.println("周一到周五休息");
}
}
//输出结果 :
周末休息
注意:
Weekday 类的构造方法一定要私有化,为了防止外界创建对象,我们只能调用Weekday中的常量,而不能随便创建对象.
这样就可以避免以上用 int 类型做星期几时存在的 2 个问题.
但是以上代码还是太过于复杂,下面通过枚举来进行优化
3. 通过枚举来创建一个常量类
//编译前代码
public enum WeekDays {
MONDAY,TUESDAY,WEDNESDAY,THURSDAY,FRIDAY,SATURDAY,SUNDAY;
}
//测试代码
public static void main(String[] args) {
Employee e = new Employee();
e.setRestDay(WeekDays.SATURDAY);
WeekDays restDay = e.getRestDay();
if (restDay == WeekDays.SATURDAY || restDay == WeekDays.SUNDAY){
System.out.println("周末休息");
} else {
System.out.println("周一到周五休息");
}
}
通过反编译可以看到编译后的 枚举类如下:
//编译后代码
public final class WeekDays extends Enum
{
public static final WeekDays MONDAY;
public static final WeekDays TUESDAY;
public static final WeekDays WEDNESDAY;
public static final WeekDays THURSDAY;
public static final WeekDays FRIDAY;
public static final WeekDays SATURDAY;
public static final WeekDays SUNDAY;
private static final WeekDays $VALUES[];
public static WeekDays[] values()
{
return (WeekDays[])$VALUES.clone();
}
public static WeekDays valueOf(String name)
{
return (WeekDays)Enum.valueOf(WeekDays, name);
}
private WeekDays(String s, int i)
{
super(s, i);
}
static
{
MONDAY = new WeekDays("MONDAY", 0);
TUESDAY = new WeekDays("TUESDAY", 1);
WEDNESDAY = new WeekDays("WEDNESDAY", 2);
THURSDAY = new WeekDays("THURSDAY", 3);
FRIDAY = new WeekDays("FRIDAY", 4);
SATURDAY = new WeekDays("SATURDAY", 5);
SUNDAY = new WeekDays("SUNDAY", 6);
$VALUES = (new WeekDays[] {
MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY
});
}
}
枚举的特点:
1. 枚举的直接父类是 java.lang.Enum,但是不能显示继承 Enum.
2. 枚举就相当于一个类,可以定义构造方法,成员变量,普通方法和抽象方法
3. 默认私有的构造方法,即使不写访问权限也是private修饰(假的构造器,底层是没有无参数构造器的).
4. 每个实例分别用一个全局常量表示,枚举类的对象是固定的,实例个数有限,不能使用new关键字.
5. 枚举实例必须位于枚举体中最开始部分,枚举实例列表的后面要有分号与其他成员相分隔.
6. 枚举实例后有花括号时,该实例是枚举类的匿名内部类对象,(看编译后的Class文件).
枚举的使用:
- 枚举中都是全局的公共的静态常量,可以直接使用枚举类名调用.
WeekDays day = WeekDays.MONDAY; - 因为java.lang.Enum类是所有枚举类的父类,所以所有的枚举对象可以调用Enum类中的方法.
String name = 枚举对象.name(); //返回枚举对象的常量名称
int ordinal = 枚举对象.ordinal(); //返回枚举对象的序号,从0 开始
String str = 枚举对象.toString(); //返回枚举对象的常量名称 编译器生成的枚举类的静态方法
枚举类型 [] values();
Weekdays [] weekdays = Weekdays.values(); // 返回当前枚举类型所有的常量,使用一个数组封装起来.
枚举类型 valueOf(String name);
Weekdays day = Weekdays.valueOf(“MONDAY”); //把一个指定名称字符串转换为当前枚举类中同名的常量. 注意: 传的字符串一定要和枚举中的常量名大小写一致,否则就会报错.从java5开始出现枚举,switch也支持操作枚举类型.
//编译前
switch (WeekDays.MONDAY){
case MONDAY: break;
case TUESDAY: break;
case WEDNESDAY: break;
}
//编译后的class文件
switch (1..SwitchMap.WeekDays[WeekDays.MONDAY.ordinal()])
{
case 1: // '\001'
case 2: // '\002'
case 3: // '\003'
default:
return;
}
说明: 底层会调用的是ordinal()方法,而ordinal()方法的返回值是int类型
总结 : switch只支持int类型,支持枚举是因为底层使用的枚举对象的ordinal()方法,而ordinal()方法的返回值是int类型.
switch支持byte,short,char 类型,是因为底层会自动进行拆箱和装箱操作,将类型提升为int类型.
从java7开始 switch支持string类型,也是因为底层在进行自动转换.
枚举的作用:
枚举主要用来表示事物固定的类型,
枚举的单例设计模式:
使用枚举创建单例很安全,即使使用反射也不能创建对象
//编译前
public enum Singleton{
INSTANCE;
}
//编译后
final class Singleton extends Enum
{
public static final Singleton INSTANCE;
private static final Singleton $VALUES[];
public static Singleton[] values()
{
return (Singleton[])$VALUES.clone();
}
public static Singleton valueOf(String name)
{
return (Singleton)Enum.valueOf(Singleton, name);
}
private Singleton(String s, int i)
{
super(s, i);
}
static
{
INSTANCE = new Singleton("INSTANCE", 0);
$VALUES = (new Singleton[] {
INSTANCE
});
}
}