定义
在某些情况下,一个类的对象是有限且固定的,比如季节类,行星类。这种实例有限且固定的类,被称为枚举类。
枚举类可以定义自己的成员变量,方法,实现一个或者多个接口,也可以定义自己的构造器。一个Java源文件最多只能定义一个public权限的枚举类,且文件名需要和这个枚举类相同。
和普通类的区别:
- 可以实现一个或者多个接口,使用enum定义的枚举类默认继了java.lang.Enum类,而不是默认继承Object类,因此枚举类不能继承其他类型的类。其中java.lang.Enum实现了Serializable接口和Comparable接口。
- 使用enum定义,非抽象的枚举类型,默认使用final修饰,因此枚举类不能派生子类。注意,即使是含有抽象方法的抽象枚举类也不能使用abstract修饰(因为系统会自动添加abstract修饰符)。
- 枚举类的构造器只能使用private修饰符,如果省略了,则默认是,如果指定则只能指定private修饰符。
- 枚举类的所有实例必须子枚举类的第一行全部列出,否则枚举类永远没法产生实例。列出这些实例的时候,系统会自动添加public static final修饰,无需程序员手动添加。
例子:
1 2 3 4 5 6 7 8 9 10 11
| // JDK1.6 中switch加入了对枚举的支持 enum Signal { GREEN, YELLOW, RED } .... switch (color) { case RED: color = Signal.GREEN; break; } ....
|
常用方法:
比较此枚举与指定对象的顺序。在该对象小于、等于或大于指定对象时,分别返回负整数、零或正整数。 枚举常量只能与相同枚举类型的其他枚举常量进行比较。
1 2 3 4 5 6 7 8 9
| // Enum 中的源码 public final int compareTo(E o) { Enum other = (Enum)o; Enum self = this; if (self.getClass() != other.getClass() && // optimization self.getDeclaringClass() != other.getDeclaringClass()) throw new ClassCastException(); return self.ordinal - other.ordinal; }
|
返回此枚举实例的名称。
返回一个包含全部枚举值的数组,可以用来遍历所有枚举值。
返回此枚举实例的名称,即枚举值。与 name() 一样。
1 2 3 4 5 6 7
| // Enum 中 name() 和 toString() public String toString() { return name; } public final String name() { return name; }
|
返回枚举值在枚举类中的索引值(从0开始),即枚举值在枚举声明中的顺序,这个顺序根据枚举值声明的顺序而定。
- ‘<’T extends Enum‘>’ valueOf()
返回带指定名称的指定枚举类型的枚举常量,名称必须与在此类型中声明枚举常量所用的标识符完全匹配(不允许使用额外的空白字符)。这个方法与toString相对应,因此重写 toString() 方法,一定要重写 valueOf()方法(我们可以重写 toString() 方法,但不能自己重写 valueOf() 方法,当我们重写 toString()方法时,valueOf() 方法会自动重写,不用我们理会。)
1 2 3 4 5 6 7
| static enum test{ A,B,C }
System.out.println(Enum.valueOf(test.class,"A").ordinal());//0 System.out.println(Enum.valueOf(test.class,"B").ordinal());//1 System.out.println(Enum.valueOf(test.class,"C").ordinal());//2
|
枚举类的成员变量,方法和构造方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69
| public enum Color {
RED("红色"), GREEN("绿色"), BLANK("白色"), YELLO("黄色"); // 成员变量 private String name; // 构造方法 private Color(String name) { this.name = name; } // get set 方法 public String getName() { return name; } public void setName(String name) { this.name = name; } }
or
public enum Day {
MONDAY("星期一"), TUESDAY("星期二"), WEDNESDAY("星期三"), THURSDAY("星期四"), FRIDAY("星期五"), SATURDAY("星期六"), SUNDAY("星期日");//记住要用分号结束
private String desc;//中文描述
/** * 私有构造,防止被外部调用 * @param desc */ private Day(String desc){ this.desc=desc; }
/** * 定义方法,返回描述,跟常规类的定义没区别 * @return */ public String getDesc(){ return desc; }
public static void main(String[] args){ for (Day day:Day.values()) { System.out.println("name:"+day.name()+ ",desc:"+day.getDesc()); } }
/** 输出结果: name:MONDAY,desc:星期一 name:TUESDAY,desc:星期二 name:WEDNESDAY,desc:星期三 name:THURSDAY,desc:星期四 name:FRIDAY,desc:星期五 name:SATURDAY,desc:星期六 name:SUNDAY,desc:星期日 */ }
|
上面的枚举类中都增加了带参数的构造器,所以在列出枚举值的时候,必须显示的传入参数。在列出枚举值的时候,实际上就是调用构造器创建枚举对象,只是这里无需使用new关键字,也无需显示的调用构造器。前面列出枚举值的时候无需传入参数,甚至无需使用括号,仅仅是因为前面的枚举类包含无参数的构造器。
枚举类实现接口
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72
| public interface Behaviour { void print(); }
public enum ColorA implements Behaviour{
RED("红色"), GREEN("绿色"), BLANK("白色"), YELLO("黄色");
// 成员变量 private String name; // 构造方法 private ColorA(String name) { this.name = name; }
// get set 方法 public String getName() { return name; } public void setName(String name) { this.name = name; }
//接口方法 @Override public void print() { System.out.println(this.name); } }
or
public enum ColorB implements Behaviour{
RED("红色"){ @Override public void print() { System.out.println(RED.name); } }, GREEN("绿色"){ @Override public void print() { System.out.println(GREEN.name); } }, BLANK("白色"){ @Override public void print() { System.out.println(BLANK.name); } }, YELLO("黄色"){ @Override public void print() { System.out.println(YELLO.name); } };
// 成员变量 private String name; // 构造方法 private ColorB(String name) { this.name = name; }
// get set 方法 public String getName() { return name; } public void setName(String name) { this.name = name; }
}
|
第二种实现中,四个枚举值都是ColorB的匿名内部子类。编译完成后会生成五个class文件,分别对应ColorB和四个枚举类值。
包含抽象方法的枚举类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47
| public enum Operation {
// 用于执行加法运算 PLUS { // 花括号部分其实是一个匿名内部子类
@Override public double calculate(double x, double y) { return x + y; }
},
// 用于执行减法运算 MINUS { // 花括号部分其实是一个匿名内部子类
@Override public double calculate(double x, double y) { // TODO Auto-generated method stub return x - y; }
},
// 用于执行乘法运算 TIMES { // 花括号部分其实是一个匿名内部子类
@Override public double calculate(double x, double y) { return x * y; }
},
// 用于执行除法运算 DIVIDE { // 花括号部分其实是一个匿名内部子类
@Override public double calculate(double x, double y) { return x / y; }
};
//为该枚举类定义一个抽象方法,枚举类中所有的枚举值都必须实现这个方法 public abstract double calculate(double x, double y);
}
|
编译上面的代码将生成五个class文件,Operation对应一个class文件,其他四个匿名内部子类分别对应一个class文件。
枚举类里面定义抽象方法的时候不能使用abstract将枚举类定义成抽象类(因为系统会自动为他添加abstract关键字),但是因为枚举类需要显示的创建枚举值,而不是作为父类,所以定义每个枚举值的时候必须为抽象方法提供实现,否则将出现编译错误。
建议阅读:
3分钟快速掌握枚举(enum)
小谈Java Enum的多态性
包含抽象方法的枚举类
深入理解Java枚举类型(enum)
上一篇:Java虚拟机的内存分区
下一篇:对象与垃圾回收