目录
一、前言:
二、枚举类型:
三、底层原理
四、应用
应用一:定义常量
底层原理详解
应用二:添加新方法
应用三:与switch结合使用
应用四:实现接口
应用五:使用接口组织枚举
一、前言:
回想单例设计模式:单例类是一个类只有一个实例,那么多例类就是一个类有多个实例,但不是无限个数的实例,而是有限个数的实例,这才能是枚举类。 枚举类是把变量的值一一列出来,变量的值只限于列举出来的值的范围内。
二、枚举类型:
- 在Java中,被 enum 关键字修饰的类型就是枚举类型,enum 的全称为 enumeration,它是 JDK 1.5 中引入的新特性。所有的枚举类型都是继承自Enum 类型。
- 它是一种特殊的数据类型,之所以特殊是因为它既是一种类(class)类型却又比类类型多了些特殊的约束,因此这些约束的存在也造就了枚举类型的简洁性、安全性以及便捷性。
- 枚举一般用于以下情况:定义常量、添加新方法、与switch结合使用、实现接口、使用接口组织枚举。
下面使用枚举定义常量,并对比未使用枚举定义常量的区别,同时介绍枚举的基本原理。
三、底层原理
见底层原理详解。
四、应用
应用一:定义常量
案例:未使用枚举类型定义常量
我们通常利用public final static 方法定义的代码如下,分别用1-6表示星期一到星期日
public class EnumWeekDay {
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;
public static void main(String[] args) {
System.out.println(EnumWeekDay .MONDAY);
System.out.println(EnumWeekDay .WEDNESDAY);
System.out.println(EnumWeekDay .THURSDAY);
System.out.println(EnumWeekDay .FRIDAY);
System.out.println(EnumWeekDay .SATURDAY);
System.out.println(EnumWeekDay .SUNDAY);
}}
问题:上述的常量定义常量的方式称为int枚举模式,这样的定义方式在类型安全和使用方便性上有不足之处,如果存在定义int值相同的变量,混淆的几率很大,编译器也不会提出任何警告。
解决方案:使用枚举类型
枚举类型现后上述int枚举模式并不提倡,相关的常量分组到一个枚举类型里,而且枚举提供了比常量更多的方法,现在我们利用枚举类型来重新定义上述的常量。
案例:使用枚举类型之后定义常量
enum EnumWeekDay {
//使用枚举方式,会自动赋值,默认值是从0开始
MONDAY, TUESDAY, WEDNESDAY,
THURSDAY, FRIDAY, SATURDAY, SUNDAY
}
进行测试:
public class WeekDayDemo {
public static void main(String[] args) {
//结果本质上都是EnumWeekDay对象,底层相当于调用了EnumWeekDay默认构造方法创建一个对象,将所有的数据存入数组
System.out.println(EnumWeekDay.MONDAY.getClass().getName());
System.out.println(EnumWeekDay.MONDAY);
System.out.println(EnumWeekDay.TUESDAY);
System.out.println(EnumWeekDay.WEDNESDAY);
System.out.println(EnumWeekDay.THURSDAY);
System.out.println(EnumWeekDay.FRIDAY);
System.out.println(EnumWeekDay.SATURDAY);
System.out.println(EnumWeekDay.SUNDAY);
System.out.println(EnumWeekDay.SUNDAY);System.out.println(EnumWeekDay.MONDAY.ordinal());
System.out.println(EnumWeekDay.TUESDAY.ordinal());
System.out.println(EnumWeekDay.WEDNESDAY.ordinal());
System.out.println(EnumWeekDay.THURSDAY.ordinal());
System.out.println(EnumWeekDay.FRIDAY.ordinal());
System.out.println(EnumWeekDay.SATURDAY.ordinal());
System.out.println(EnumWeekDay.SUNDAY.ordinal());
}
}运行结果 com.JavaSe.emum.EnumWeekDay 星期一 星期二 星期三 星期四 星期五 星期六 星期日 0 1 2 3 4 5 6
通过案例可以看出,使用枚举的结果本质上底层调用了EnumWeekDay默认构造方法,创建了多个EnumWeekDay实例对象,对象起名分别为MONDAY到SUNDAY,将枚举数据实例存入一个数组的里面,ordinal是数组的下标。(后面原理部分会讲)
案例:使用枚举的有参构造
步骤:
- 先定义枚举实例序列,枚举实例后的括号,表示调用私有构造方法;
- 必须在enum实例序列的最后添加一个分号;
- 创建私有变量;
- 编写私有有参构造方法;
- 覆盖toString()方法
public enum EnumWeekDay {
//1、定义枚举常量, 2、并添加分号
MONDAY("星期一"), TUESDAY("星期二"), WEDNESDAY("星期三"),
THURSDAY("星期四"), FRIDAY("星期五"), SATURDAY("星期六"), SUNDAY("星期日");// 3、创建私有变量;
private String weekday;//4、编写私有有参构造方法;
private EnumWeekDay(String weekday) {
System.out.println(weekday);
this.weekday = weekday;
}
//5、覆盖toString()方法
@Override
public String toString() {
return this.weekday;
}}
运行结果 星期一 星期二 星期三 星期四 星期五 星期六 星期日
底层原理详解:
实际上在使用关键字enum创建枚举类型并编译后,编译器会为我们生成一个相关的类,
这个类继承了Java API中的java.lang.Enum类。以上面案例为例:使用javac进行编译EnumWeekDay.java:javac EnumWeekDay.java,生成EnumWeekDay.class,对EnumWeekDay.class反编译如下:
public enum EnumWeekDay {
MONDAY("星期一"),
TUESDAY("星期二"),
WEDNESDAY("星期三"),
THURSDAY("星期四"),
FRIDAY("星期五"),
SATURDAY("星期六"),
SUNDAY("星期日");
private String weekday;
// $FF: synthetic field
private static final EnumWeekDay[] $VALUES
= new EnumWeekDay[]{MONDAY, TUESDAY, WEDNESDAY,
THURSDAY, FRIDAY, SATURDAY, SUNDAY};private EnumWeekDay(String var3) {
System.out.println(var3);
this.weekday = var3;
}public String toString() {
return this.weekday;
}
}
再进一步分析:
final class EnumWeekDay extends Enum {
private String weekday;
//私有构造函数
private EnumWeekDay(String name)
{
this.weekday =weekday;
}//前面定义的7种枚举实例
public static final EnumWeekDay MONDAY;
public static final EnumWeekDay TUESDAY;
public static final EnumWeekDay WEDNESDAY;
public static final EnumWeekDay THURSDAY;
public static final EnumWeekDay FRIDAY;
public static final EnumWeekDay SATURDAY;
public static final EnumWeekDay SUNDAY;
private static final EnumWeekDay $VALUES[];static
{
//实例化枚举实例
MONDAY = new EnumWeekDay("星期一");
TUESDAY = new EnumWeekDay("星期二");
WEDNESDAY = new EnumWeekDay("星期三");
THURSDAY = new EnumWeekDay("星期四");
FRIDAY = new EnumWeekDay("星期五");
SATURDAY = new EnumWeekDay("星期六");
SUNDAY = new EnumWeekDay("星期日");
$VALUES = (new EnumWeekDay[] {
MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY
});}
//编译器为我们添加的静态的values()方法
public static EnumWeekDay[] values()
{
return (EnumWeekDay[])$VALUES.clone();
}
//编译器为我们添加的静态的valueOf()方法,注意间接调用了Enum也类的valueOf方法
public static EnumWeekDay valueOf(String s)
{
return (EnumWeekDay)Enum.valueOf(./EnumWeekDay, s);
}}
从反编译的代码看出,EnumWeekDay类(注意该类是final类型的,将无法被继承)继承自java.lang.Enum类,同时编译器还帮助我们生成了7个EnumWeekDay类型的实例对象分别对应枚举中定义的7个日期,充分说明了使用关键字enum定义的EnumWeekDay类型中的每种日期枚举常量也是实实在在的EnumWeekDay实例对象。
类中values()方法的作用就是获取枚举类中的所有变量,并作为数组返回,valueOf()根据参数获取1个对应枚举变量,测试用例如下:
for (EnumWeekDay weekDay:EnumWeekDay.values()) {
System.out.println(weekDay);
}System.out.println(EnumWeekDay.valueOf("MONDAY"));
应用二:添加新方法
Java 为枚举类型提供了一些内置的方法,同时枚举常量也可以有自己的方法。此时要注意必须在枚举实例的最后一个成员后添加分号,而且必须先定义枚举实例。
步骤:
- 先定义枚举实例序列,枚举实例后的括号,表示调用私有构造方法;
- 必须在enum实例序列的最后添加一个分号;
- 创建私有变量;
- 编写私有有参构造方法;
- 添加新方法;
- 覆盖toString()方法。
public enum EnumWeekDay {
//1、定义枚举常量, 2、并添加分号
MONDAY("星期一"), TUESDAY("星期二"), WEDNESDAY("星期三"),
THURSDAY("星期四"), FRIDAY("星期五"), SATURDAY("星期六"), SUNDAY("星期日");
// 3、创建私有变量;
private String weekday;//4、编写私有有参构造方法;
private EnumWeekDay(String weekday) {
System.out.println(weekday);
this.weekday = weekday;
}
//5、覆盖toString()方法
@Override
public String toString() {
return this.weekday;
}
//6、添加新方法
public static EnumWeekDay getWeekDay(int num) {
switch(i) {
case 1:
return EnumWeekDay.MONDAY;
case 2:
return EnumWeekDay.TUESDAY;
case 3:
return EnumWeekDay.WEDNESDAY;
case 4:
return EnumWeekDay.THURSDAY;
case 5:
return EnumWeekDay.FRIDAY;
case 6:
return EnumWeekDay.SATURDAY;
case 7:
return EnumWeekDay.SUNDAY;
default:
System.out.println("wrong number!");
return null;
}
}
}class EnumWeekDayDemo{ public static void main(String[] args) { System.out.println(EnumWeekDay.getWeekDay(1).toString()); System.out.println(EnumWeekDay.getWeekDay(2).toString()); System.out.println(EnumWeekDay.getWeekDay(3).toString()); System.out.println(EnumWeekDay.getWeekDay(4).toString()); System.out.println(EnumWeekDay.getWeekDay(5).toString()); System.out.println(EnumWeekDay.getWeekDay(6).toString()); System.out.println(EnumWeekDay.getWeekDay(7).toString()); } }运行结果 星期一 星期二 星期三 星期四 星期五 星期六 星期日
应用三:与switch结合使用
关于使用switch进行条件判断时,条件参数一般只能是整型,字符型。而枚举型确实也被switch所支持,在java 1.7后switch也对字符串进行了支持。这里我们简单看一下switch与枚举类型的使用:
public enum EnumWeekDay {
//1、定义枚举常量, 2、并添加分号
MONDAY("星期一"), TUESDAY("星期二"), WEDNESDAY("星期三"),
THURSDAY("星期四"), FRIDAY("星期五"), SATURDAY("星期六"), SUNDAY("星期日");
// 3、创建私有变量;
private String weekday;//4、编写私有有参构造方法;
private EnumWeekDay(String weekday) {
System.out.println(weekday);
this.weekday = weekday;
}
//5、覆盖toString()方法
@Override
public String toString() {
return this.weekday;
}
}与switch结合测试类:
public class WeekDayDemo {
public static void main(String[] args) {
EnumWeekDay weekDay = EnumWeekDay .MONDAY;
getDay(weekDay);
}public static void getDay(EnumWeekDay weekDay){
switch (weekDay){
case MONDAY:
System.out.println(MONDAY);
break;
case TUESDAY:
System.out.println(TUESDAY);
break;
case WEDNESDAY:
System.out.println(WEDNESDAY);
break;
case THURSDAY:
System.out.println(THURSDAY);
break;
case FRIDAY:
System.out.println(FRIDAY);
break;
case SATURDAY:
System.out.println(SATURDAY);
break;
case SUNDAY:
System.out.println(SUNDAY);
break;
default:
System.out.println("输入有误");
break;
}
}
}
应用四:实现接口
由于Java单继承的原因,enum类并不能再继承其它类,但并不妨碍它实现接口,因此enum类同样是可以实现多接口的,如下:
interface food{
void eat();
}interface sport{
void run();
}public enum EnumDemo2 implements food ,sport{
FOOD,
SPORT,
; //分号分隔@Override
public void eat() {
System.out.println("eat.....");
}@Override
public void run() {
System.out.println("run.....");
}public static void main(String[] args) {
EnumDemo2.FOOD.eat();
EnumDemo2.SPORT.run();
}
}
应用五:使用接口组织枚举
有时候,我们可能需要对一组数据进行分类,比如对食物分类,食物包含dessert(点心)、Coffee等,而且希望这些都属于food类型,此时可以利用接口来组织,因此利用一个枚举嵌套枚举的方式,可以统一管理食物中的数据了。如下(代码引用自Thinking in Java):
public interface Food {
enum Coffee implements Food{
BLACK_COFFEE,DECAF_COFFEE,LATTE,CAPPUCCINO
}
enum Dessert implements Food{
FRUIT, CAKE, GELATO
}
}
public class TypeOfFood {
public static void main(String[] args) {
Food food = Dessert.GELATO;
food = Coffee.CAPPUCCINO;
}
}