模拟枚举,其实枚举编译后就是如此:
package cn.zyj13.review;
public class EnumTest {
public static void main(String[] args) {
WeekDay mon=WeekDay.MON;
System.out.println(mon);
System.out.println(mon.nextDay());
}
}
package cn.zyj13.review;
public abstract class WeekDay {
//1、私有构造函数
private WeekDay(){}
//2、每个元素分别用一个公有的静态成员变量表示
public final static WeekDay MON =new WeekDay() {
//3、可以有若干个公有方法或抽象方法。
//例如,要提供nextDay()方法必须是抽象的。采用抽象方法定义的nextDay()就将大量的ifelse语句转移成了一个个独立的类
@Override
public WeekDay nextDay() {
return TUE ;
}
@Override
public String toString() {
return "Monday";
}
};
public final static WeekDay TUE =new WeekDay() {
@Override
public WeekDay nextDay() {
return WED ;
}
@Override
public String toString() {
return "Tuesday";
}
};
public final static WeekDay WED =new WeekDay() {
@Override
public WeekDay nextDay() {
return THU ;
}
@Override
public String toString() {
return "Wednesday";
}
};
public final static WeekDay THU =new WeekDay() {
@Override
public WeekDay nextDay() {
return FRI ;
}
@Override
public String toString() {
return "Thursday";
}
};
public final static WeekDay FRI =new WeekDay() {
@Override
public WeekDay nextDay() {
return SAT ;
}
@Override
public String toString() {
return "Friday";
}
};
public final static WeekDay SAT =new WeekDay() {
@Override
public WeekDay nextDay() {
return SUN ;
}
@Override
public String toString() {
return "Saturday";
}
};
public final static WeekDay SUN =new WeekDay() {
@Override
public WeekDay nextDay() {
return MON ;
}
@Override
public String toString() {
return "Sunday";
}
};
public abstract WeekDay nextDay();
public abstract String toString();
// 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";
// }
// }
}
枚举实例:
package cn.zyj1416.review;
public class EnumTest {
public static void main(String[] args) {
Weekday weekday1=Weekday.FRI;
System.out.println(weekday1);//枚举自动实现toString方法 //FRI
System.out.println(weekday1.name()); //FRI
System.out.println(weekday1.ordinal());//注意这个结果//5
System.out.println(Weekday.MON); //MON
System.out.println(Weekday.valueOf("MON")); //MON
System.out.println(Weekday.values().length); //7
TrafficLamp red=TrafficLamp.RED;
System.out.println(red);
}
public enum Weekday{
SUN(1),MON(),TUE,WED,THU,FRI,SAT;//元素列表必须放在首行
private Weekday(){System.out.println("first");}//构造函数必须私有
private Weekday(int day){System.out.println("second");}
}
public enum TrafficLamp{
//内部类。如果枚举元素后面没有大括号对,那是不会生成内部类的。
RED(30){
public TrafficLamp nextLamp(){
return GREEN;
}
},
GREEN(45){
public TrafficLamp nextLamp(){
return YELLOW;
}
},
YELLOW(5){
public TrafficLamp nextLamp(){
return RED;
}
};
public abstract TrafficLamp nextLamp();
private int time;
private TrafficLamp(){}
private TrafficLamp(int time){this.time = time;}
public String toString(){
if (this==RED) {
return "红";
} else if(this==GREEN){
return "绿";
}else{
return "黄";
}
}
}
}
一、为什么要有枚举
枚举就是要让某个类型的变量的取值只能为了若干个固定值中的一个,否则,编译器就会报错。枚举可以让编译器在编译的时候就可以控制源程序中填写的非法值,普通变量的方式在开发阶
段无法实现这一目标
二、用普通类如何实现枚举功能,定义一个Weekday的类来模拟枚举功能
1、私有构造函数
2、每个元素分别用一个公有的静态成员变量表示
3、可以有若干个公有方法或抽象方法。例如,要提供nextDay()方法必须是抽象的。采用抽象方法定义的nextDay()就将大量的ifelse语句转移成了一个个独立的类
三、枚举的基本应用
举例:定义一个Weekday的枚举
扩展:所有枚举类都继承了Enum的方法,下面我们详细介绍这些方法。
(1) ordinal()方法: 返回枚举值在枚举类种的顺序。这个顺序根据枚举值声明的顺序而定。
Color.RED.ordinal(); //返回结果:0
Color.BLUE.ordinal(); //返回结果:1
(2) compareTo()方法: Enum实现了java.lang.Comparable接口,因此可以比较象与指定对象的顺序。Enum中的compareTo返回的是两个枚举值的顺序之差。当然,前提是两个枚举值
必须属于同一个枚举类,否则会抛出ClassCastException()异常。(具体可见源代码)
Color.RED.compareTo(Color.BLUE); //返回结果 -1
(3) values()方法: 静态方法,返回一个包含全部枚举值的数组。
Color[] colors=Color.values();
for(Color c:colors){
System.out.print(c+",");
}//返回结果:RED,BLUE,BLACK YELLOW,GREEN,
(4) toString()方法: 返回枚举常量的名称。
Color c=Color.RED;
System.out.println(c);//返回结果: RED
(5) valueOf()方法: 这个方法和toString方法是相对应的,返回带指定名称的指定枚举类型的枚举常量。
Color.valueOf("BLUE"); //返回结果: Color.BLUE
(6) equals()方法: 比较两个枚举类对象的引用。
总结:枚举是一种特殊的类,而且是一个不可以被继承的final类。其中的每个元素都是该类的一个实例对象,而且是该类的类型的类静态常量,例如可以调用WeekDay.SUN.getClass().getName()和WeekDay.class.getName()
1、枚举就相当于一个类,其中也可以定义构造方法、成员变量、普通方法和抽象方法。
2、枚举元素必须位于枚举体中的最开始部分,枚举元素列表的后面有分号于其他成员隔开。把枚举中的成员方法(包括构造方法)和变量等放在枚举元素额度前面,编译器报告错误。
3、带构造方法的枚举
构造方法必须定义成私有的。这样可以保证外部代码无法新构造枚举类的实例。这也是完全符合情理的,因为我们知道枚举值是public static final的常量而已。 但枚举类的方法和数据域
可以允许外部访问。
如果有多个构造方法,改如何选择哪个构造方法?
枚举元素MON和MON()的效果一样,都是调用默认的构造方法。
4、带方法的枚举
定义枚举TrafficLamp。
实现普通的next方法。
实现抽象的next方法;每个元素分别是有枚举类的子类来生成额度实例对象,这些子类采用类似内部类的方法进行定义。
增加上表示时间的构造方法。
5、枚举只有一个成员时,就可以作为一种单例的实现方法。
单例是日常开发中经常会碰到的一种模式,最常见的写法如下所示:
Java代码
public class Singleton {
private Singleton() {}
private static final class Holder {
static final Singleton instance = new Singleton();
}
public static Singleton getInstance() {
return Holder.instance;
}
}
这样写不仅达到了单例的效果,而且还是延迟加载,至于为什么不明白的童鞋可以 google 或 百度一下。( 这称为 lazy initialization holder class 模式 )
其实使用枚举可以很容易地实现单例。
Java代码
public enum Singleton {
INSTANCE {
public void someMethod() {
// . . .
}
};
protected abstract void someMethod();
}
枚举类型 INSTANCE 就是一个单例,类型为 Singleton。
注:双检查锁只有在 jdk 1.5 及以上版本才能达到单例的效果的。
6、枚举类可以在switch语句中使用。
7、枚举实现接口
所有的枚举都继承自java.lang.Enum类。由于Java 不支持多继承,所以枚举对象不能再继承其他类。
Java代码
public interface Behaviour {
void print();
String getInfo();
}
public enum Color implements Behaviour{
RED("红色", 1), GREEN("绿色", 2), BLANK("白色", 3), YELLO("黄色", 4);
// 成员变量
private String name;
private int index;
// 构造方法
private Color(String name, int index) {
this.name = name;
this.index = index;
}
//接口方法
@Override
public String getInfo() {
return this.name;
}
//接口方法
@Override
public void print() {
System.out.println(this.index+":"+this.name);
}
}
8、使用接口组织枚举
public interface Food {
enum Coffee implements Food{
BLACK_COFFEE,DECAF_COFFEE,LATTE,CAPPUCCINO
}
enum Dessert implements Food{
FRUIT, CAKE, GELATO
}
}
9、关于枚举集合的使用
java.util.EnumSet和java.util.EnumMap是两个枚举集合。EnumSet保证集合中的元素不重复;EnumMap中的 key是enum类型,而value则可以是任意类型。关于这个两个集合的使用就不在这里
赘述,可以参考JDK文档。
关于枚举的实现细节和原理请参考:《ThinkingInJava》第四版
因为枚举元素必须在定义之后引用,所以无法再构造方法中彼此相互引用,所以,相反方向和下一个方向的灯用字符串形式表示。