1. 什么是枚举

所谓枚举是指将变量的值一一列举出来,变量的值只限于列举出来的值的范围内。比如星期,一年中的四季,颜色值等都可以使用枚举进行列举出来。

 

2. 枚举类的前世今生

在jdk5以前的,要使用枚举那是不可能的,因为那个时候还没有呢,从5之后就有了枚举。其实一个枚举中的实例对象都是被static final 修饰的,因此我们可以使用普通的类进行模拟。

//
// 不带抽象方法
public class WeekDay {
// 禁止创建对象
private WeekDay(){
}
public final static WeekDay MON = new WeekDay();
public final static WeekDay TUE = new WeekDay();
public final static WeekDay WED = new WeekDay();
public final static WeekDay THU = new WeekDay();
public final static WeekDay FRI = new WeekDay();
public final static WeekDay SAT = new WeekDay();
public final static WeekDay SUN = new WeekDay();
public WeekDay nextDay(){
    if(this==MON)
        return TUE; 
    else if(this==TUE)
        return WED;
    else if(this==WED)
        return THU;
    else if(this==THU)
        return FRI;
    else if(this==FRI)
        return SAT;
    else
        return SUN;
}
public WeekDay aboveDay(){
    if(this==MON)
        return SUN;
    else if(this==TUE)
        return MON;
    else if(this==WED)
        return TUE;
    else if(this==THU)
        return WED;
    else if(this==FRI)
        return THU;
    else
        return SAT;
}
// Sunday(星期天)、Monday(星期一)、Tuesday(星期二)
// Wednesday(星期三)、Thursday(星期四)、Friday(星期五)、Saturday(星期六)。 
  public String toString(){
      if(this == MON)
          return "Monday";
      else if(this == TUE)
          return "Tuesday";
      else if(this == WED)
          return "Wednesday";
      else if(this == THU)
          return "Thursday";
      else if(this == FRI)
          return "Friday";
      else if(this == SAT)
          return "Saturday";
      else
          return "Sunday";
  }
//
 public int ordinal() {
    if(this == MON)
        return 0;
    else if(this == TUE)
        return 1;
    else if(this == WED)
        return 2;
    else if(this == THU)
        return 3;
    else if(this == FRI)
        return 4;
    else if(this == SAT)
        return 5;
    else
        return 6;
 }
}
//
// 带抽象方法和构造函数的
public abstract class WeekDay1 {
模拟枚举中的成员实例
    public final static WeekDay1 MON = new WeekDay1(1){
 
    @Override
    public WeekDay1 nextDay() {
        return TUE;
    }
 
    @Override
    public WeekDay1 aboveDay() {
        return SUN;
};
    public final static WeekDay1 TUE = new WeekDay1(2){
@Override 
    public WeekDay1 nextDay() {
        return WED;
    }
    @Override
    public WeekDay1 aboveDay() {
        return TUE;
};
    public final static WeekDay1 WED = new WeekDay1(3){
 
    @Override
    public WeekDay1 nextDay() {
        return THU;
    }
    @Override
    public WeekDay1 aboveDay() {
        return TUE;
    }
    };
    public final static WeekDay1 THU = new WeekDay1(4){
 
    @Override
    public WeekDay1 nextDay() {
        return FRI;
    }
    @Override
    public WeekDay1 aboveDay() {
        return WED;
    }
    };
    public final static WeekDay1 FRI = new WeekDay1(5){
 
    @Override
    public WeekDay1 nextDay() {
        return SAT;
    }
    @Override
    public WeekDay1 aboveDay() {
        return THU;
    }
    };
    public final static WeekDay1 SAT = new WeekDay1(6){
 
    @Override
    public WeekDay1 nextDay() {
        return SUN;
    }
    @Override
        public WeekDay1 aboveDay() {
        return FRI;
    }
    };
    public final static WeekDay1 SUN = new WeekDay1(0){
 
    @Override
    public WeekDay1 nextDay() {
        return null;
    }
    @Override
    public WeekDay1 aboveDay() {
        return null;
    }
    };
    private int index;
// 默认构造器
// 自定义构造器
        this.index = index;
    }
    public abstract WeekDay1 nextDay();
    public abstract WeekDay1 aboveDay();
 
 // Sunday(星期天)、Monday(星期一)、Tuesday(星期二)
       // Wednesday(星期三)、Thursday(星期四)、Friday(星期五)、Saturday(星期六)
    public String toString(){
        if(this == MON)
             return "Monday";
        else if(this == TUE)
             return "Tuesday";
        else if(this == WED)
             return "Wednesday";
        else if(this == THU)
             return "Thursday";
        else if(this == FRI)
             return "Friday";
        else if(this == SAT)
             return "Saturday";
        else
             return "Sunday";
    }
    public int ordinal(){
        return this.index;
    }
}

自从有了枚举之后,我们就可以这样来定义一个枚举了,给我们的开发带来了诸多的方便。枚举类中的多种常用的方法我们都可以使用了,相当的方便。

public enum WeekDay{
    MON, TUE, WED, THU, FRI, SAT, SUN;
}

 

3. 枚举的特点

1) 用enum定义的枚举默认继承了java.lang.Enum类而不是继承了Object类。其中java.lang.Enum类实现了java.lang.Serializable和java.lang.Comparable两个接口。

2) 枚举类的构造方法只能使用private作为访问修饰符,如果省略了构造方法的访问修饰符,那么他会默认使用private作为访问修饰符。

3) 枚举类的所有实例成员都会显示的列出,系统会自动添加public static final进行修饰。无需我们手动进行添加。

 

4. 枚举的遍历

枚举的遍历我们使用增强for循环进行遍历,如下代码显示:

// 不带构造方法和带构造方法枚举
public enum WeekDay{
     MON, TUE, WED, THU, FRI, SAT, SUN;
 
}

因为WeekDay.values()返回的是一个WeekDay类型的数组。

for(WeekDay w : WeekDay.values()){
System.out.println(w);
}

5. 枚举的常用方法

int compareTo方法,将两个枚举实例进行比较

String name() 返回枚举实例的名称

int ordinal() 返回枚举值在枚举中的索引

String toString() 返回枚举的实例名称 比name更常用

public static valueOf(String name)  根据字符串形式的枚举值得到一个枚举实例

public class EnumTest2 {
    public static void main(String[] args) {
 
        WeekDay week = WeekDay.MON;
        System.out.println(week.toString());
        System.out.println(week.name());
        System.out.println(week.ordinal());
// 使用一个字符串返回一个枚举实例
        WeekDay week2 = WeekDay.valueOf("TUE");
        System.out.println(week2.toString());
        WeekDay week3 = WeekDay.valueOf(WeekDay.class, "FRI");
        System.out.println(week3.name());
    }
 
// 
    public enum WeekDay{
        MON, TUE, WED, THU, FRI, SAT, SUN;
    }
}

6. 枚举的高级用法

在一个枚举类中我们可以自定义构造方法,还可以定义抽象的方法和非抽象的方法。枚举实例要放置在最前边,枚举类中的成员变量和方法都放在后边

// 不带构造方法和带构造方法枚举
public enum WeekDay{
MON(1), TUE(), WED, THU, FRI, SAT, SUN;
WeekDay(){
System.out.println("first");
}
WeekDay(int index){
System.out.println("second"+index);
}
}
要是枚举类中有抽象方法,那么枚举实例在开始就要对其复写。
public class Test {
public static void main(String[] args) {
 
WeekDay week = WeekDay.MON;
System.out.println(week.toString());
System.out.println(week.ordinal());
week.getWeekday();
}
// 带构造方法和抽象方法以及非抽象方法的枚举
public enum WeekDay{
MON(1){
@Override
public WeekDay nextDay() {
return TUE;
}},
TUE(){
@Override
public WeekDay nextDay() {
return WED;
}}, 
WED{
@Override
public WeekDay nextDay() {
return THU;
}},
THU{
 
@Override
public WeekDay nextDay() {
return FRI;
}},
FRI{
 
@Override
public WeekDay nextDay() {
return SAT;
}},
SAT{
 
@Override
public WeekDay nextDay() {
return SUN;
}},
SUN{
@Override
public WeekDay nextDay() {
return MON;
}};
WeekDay(){
System.out.println("first");
}
WeekDay(int index){
System.out.println("second"+index);
}
public abstract WeekDay nextDay();
public void getWeekday(){
System.out.println("The weekday is "+SAT.toString()+" and "+SUN.toString());
}
}
}

 

7. 枚举应用的实例,交通灯系统

public enum Lamp {

// 每个枚举元素各表示一个方向的控制灯 

S2N("N2S","S2W",false),S2W("N2E","E2W",false),

E2W("W2E","E2S",false),E2S("W2N","S2N",false),

下面元素表示与上面的元素的相反方向的灯,它们的“相反方向灯”和“下一个灯”应忽略不计!

   N2S(null,null,false),N2E(null,null,false),

   W2E(null,null,false),W2N(null,null,false),

由南向东和由西向北等右拐弯的灯不受红绿灯的控制,所以,可以假想它们总是绿灯

S2E(null,null,true),E2N(null,null,true),

N2W(null,null,true),W2S(null,null,true);

private Lamp(String opposite,String next,boolean lighted){
        this.opposite = opposite;
        this.next = next;
        this.lighted = lighted;
    }
 
// 当前灯是否为绿  
    private boolean lighted;
 // 与当前灯同时为绿的对应方向  
    private String opposite;
 // 当前灯变红时下一个变绿的灯
    private String next;
    public boolean isLighted(){
        return lighted;
    }
 
        // 某个灯变绿时,它对应方向的灯也要变绿
    public void light(){
        this.lighted = true;
        if(opposite != null){
            Lamp.valueOf(opposite).light();
        }
        System.out.println(name() + " lamp is green,下面总共应该有6个方向能看到汽车穿过!");
 
    }
 
    //  某个灯变红时,对应方向的灯也要变红,并且下一个方向的灯要变绿
       // @return 下一个要变绿的灯
    public Lamp blackOut(){
        this.lighted = false;
        if(opposite != null){
            Lamp.valueOf(opposite).blackOut();
        }        
 
        Lamp nextLamp= null;
        if(next != null){
            nextLamp = Lamp.valueOf(next);
            System.out.println("绿灯从" + name() + "-------->切换为" + next);            
            nextLamp.light();
        }
        return nextLamp;
    }
}

8. 总结

枚举这种全新的类型的出现很方便,这种类型像是对象也像数组。其实枚举成员也是一个实例,对于一个变量有限的值进行描述的时候,我们提倡使用枚举。枚举中封装的方法都很好用,可以提高效率,对每个值都能进行详细的描述。当这个枚举中有一个枚举值的时候我们可以当做单例设计模式来使用。枚举的出现,简化了开发,但是枚举的高级用法也是相当复杂,要是使用不当会降低代码的可读性。