Java JDK1.5新特性 – 枚举
一.枚举定义
定义:枚举是使用enum声明定义的特殊class,但是它并不继承自java.lang.Object类,它是继承自java.lang.Enum<E>这个类,这个类是所有 Java 语言枚举类型的公共基本类,其中java.lang.Enum类实现了java.lang.Serializable和java.lang.Comparable两个接口。
二. 枚举的特点
1. 枚举既然是一个特殊的类,那么它也可以有构造方法,只不过枚举中的构造方法都是私有的,只有在内部创建枚举值(也可以说是这个枚举类型的对象)的时候才使用,绝对不允许有public构造器。这样可以保证外部代码无法新构造枚举类的实例,构造器可以有多个,调用哪个即初始化相应的值。(因为我们知道枚举值是public static final的常量而已。 但枚举类的方法和数据域可以允许外部)。
2. 每个元素(枚举值)都是public和static、final修饰的,也就是我们经常使用的常量定义方式,所以一般枚举值名称都是全部使用大写字母表示,可以用枚举类型名称直接调用,就跟普通类中的静态属性和方法一样,可以使用类名称.静态成员直接调用一样。
3. 枚举中枚举值只能在声明时给定,编译期之后或运行期是不能想普通类那样new对象的,所以枚举的元素是稳定且固定的,而且元素都是有限的。
4. 一般swtich只能使用byte、short、int、char四种基本数据类型作为值,但是枚举也可以作为switch语句的值使用。
5. 枚举类里定义抽象方法时,无需显示使用abstract关键字将枚举类定义成抽象类,但因为枚举类需要显示创建枚举值,而不是作为父类,所以定义每个枚举值时必须为抽象方法提供实现,否则将出项编译错误,通常是在内部使用匿名内部类实现方式比较方便。
6. 通过enum关键字定义枚举类,枚举类是一个特殊的类,每个元素都是该类的一个实例对象。
7. 如果调用者想打印枚举类中元素的信息,需由编写此类的人定义toString方法。
8. 枚举类是一个class,而且是一个不可被继承的final类,其中的元素都是类静态常量。
9. 枚举就相当于一个类,其中也可以定义构造方法、成员变量、普通方法和抽象方法。
10. 枚举元素必须位于枚举体中的最开始部分,枚举元素列表的后要有分号与其他成员分隔。把枚举中的成员方法或变量等放在枚举元素的前面,编译器报告错误。
三.为什么要使用枚举?
1. 假如现在有一个变量,要给它赋值,但是这个变量的取值只能为若干个固定值中的一个,否则编译就错误,减少运行时候的误差和错误,那么这个时候就要使用枚举,在枚举类中定义限定的几个可使用的枚举元素,这样就可以很安全和方便的给变量赋值了。
2. 在编译时期就会发现错误,表明值不符合,减少了运行时期的错误。
例如:
A. 要定义星期几或性别的变量,该怎么定义?假设用1-7分别表示星期一到星期日,但有人可能会写成int weekday = 0;或即使使用常量方式也无法阻止意外。
B. 枚举就是要让某个类型的变量的取值只能为若干个固定值中的一个,否则,编译器就会报错。枚举可以让编译器在编译时就可以控制源程序中填写的非法值,普通变量的方式在开发阶段无法实现这一目标。
练习代码1:
/* * 用普通类如何实现枚举功能,定义一个Weekday的类来模拟枚举功能。 1、私有的构造方法 2、每个元素分别用一个公有的静态成员变量表示 3、可以有若干公有方法或抽象方法。采用抽象方法定义nextDay就将大量的if.else语句转移成了一个个独立的类。 */ package cn.itheima; public abstract class WeekDay { private WeekDay(){} public final static WeekDay SUN=new WeekDay(){ public WeekDay nextDay(){ return MON; } }; public final static WeekDay MON=new WeekDay(){ public WeekDay nextDay(){ return SUN; } }; public abstract WeekDay nextDay(); public String toString(){ return this==SUN?"SUM":"MON"; } }
四.枚举的应用
1. 枚举中静态方法
A. valueOf(Stringe);
将给定的字符串转为该枚举中的对应元素或对象。
B. values();
返回一个包含枚举类中的所有枚举元素的数组。
2. 非静态的方法
A. StringtoString();返回枚举的名称
B. intordinal();返回枚举值在枚举类中的顺序,按照定义的顺序排。
C. ClassgetClass();获取对应的类名
D. Stringname();返回此枚举常量的名称,在其枚举声明中对其进行声明。
练习代码2:
public class WeekdayTest { public static void main(String[] args) { Weekday[] days = Weekday.values(); for(Weekday day : days) { System.out.println("今天是: "+day); System.out.println("明天是:"+day.nextDay()); System.out.println("==================="); } } //定义一个内部枚举类 enum Weekday { //每个元素使用匿名内部类的方法来实现抽象方法,返回当天的下一天是星期几 MON { @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; } }; //定义一个抽象方法来表示下一天是星期几 public abstract Weekday nextDay(); } }
练习代码3:
package cn.itheima; public class EnumDemo { public static void main(String[] args) { WeekDay weekDay=WeekDay.MON; System.out.println(weekDay);//输出枚举常量名 System.out.println(weekDay.name());//输出对象名 System.out.println(weekDay.getClass());//输出对应类 System.out.println(weekDay.toString());//输出枚举对象名 System.out.println(weekDay.ordinal());//输出此对象在枚举常量的次序 System.out.println(WeekDay.valueOf("WED"));//将字符串转化为枚举常量 System.out.println(WeekDay.values().length);//获取所以的枚举元素,并打印其长度 } //定义枚举内部类 public enum WeekDay{ SUN(1),MON,TUE,WED,THI,FRI,SAT;//分号可有可无,但如果下面还有方法或其他成员时,分号不能省。 //而且当有其他方法时,必须在这些枚举变量的下方。 //无参构造器 private WeekDay(){ System.out.println("First"); } //带参数的构造器 private WeekDay(int day){ System.out.println("Second"); } } }
练习代码4:
public class EnumTest { public enum TrafficLamp{ RED(30){ public TrafficLamp nextLamp(){ return GREEN; } }, GREEN(30){ public TrafficLamp nextLamp(){ return YELLOW; } }, YELLOW(5){ public TrafficLamp nextLamp(){ return RED; } }; private int time; //构造器 private TrafficLamp(int time){ this.time=time;} //抽象方法 public abstract TrafficLamp nextLamp(); } public static void main(String[] args) { TrafficLamp[] tls = TrafficLamp.values(); for(TrafficLamp tl : tls ) { System.out.println( "当前亮起的灯是:" +tl); System.out.println( "当前灯亮起的时长是:" +tl.time); System.out.println( "下一个亮起的等是:" +tl.nextLamp()); } }