枚举类型概述
Java中所有的枚举类型都是java.lang.Enum的子类。
为什么需要枚举?
- 一些方法在运行时,它需要的数据不能是任意的,而必须是一定范围内的值,此类问题在JDK5以前采用自定义带有枚举功能的类解决,Java5以后可以直接使用枚举予以解决
创建枚举格式:
enum 枚举类型名称 {
枚举对象1名称,
枚举对象2名称,
… ,
枚举对象n名称;
}
枚举类特点
- 每个枚举常量代表某枚举类的一个实例,枚举常量在枚举类型装入并初始化时自动创建。
- 除了定义时指定的枚举常量,枚举类型不会有其他实例。(实例用枚举名调用,方法用实例调用或用static修饰用枚举名调用)
- 枚举类型定义不能使用extends短语,但隐含地扩展lang.Enum抽象类。枚举类型不能用final修饰,但也不能被扩展。
- 枚举类型中,其他语法成分必须出现在枚举常量列表的后面
- 枚举类是特殊的java类,是单例模式,枚举类的构造方法必须是私有的,因为实例已经创建好的是固定的,不能做修改
- 所有枚举值都是public,static,final的。注意这一点只是针对于枚举值,我们可以和在普通类里面定义变量一样定义其它任何类型的非枚举变量,这些变量可以用任何你想用的修饰符。
- 枚举的所有成员,都默认是public static final类型的。且必须要第一行开始声明。必须在,(逗号)分开。
- 枚举中的构造方法必须是private,可以重载。
- 枚举默认就是abstract的,不可以实例化。
- 枚举中可以拥有abstract抽像方法。
- 枚举类型可以直接用于switch语句,这个功能看起来是突破了Java中switch只能用于整数和字符的限制,不过其实是Java编译器的障眼法,Java编译器会自动在枚举成员上调用ordinal()方法,例如:Java代码
-
Weekday wd = Weekday.FRIDAY; switch (wd) { case MONDAY: System.out.println("这个星期才刚开始,慢慢等吧"); break; }
- 如果想遍历Weekday,那么可以使用它隐含的静态方法values(),这个方法在文档中找不到定义,是Java编译器自己加上去的,很奇怪!例如: Java代码
for (Weekday wd : Weekday.values()) {
System.out.println(wd + ", 顺序: " + wd.ordinal());
}
枚举类型应用
其作用是将一组相关的常量定义在一个类型中,这样在使用时就只能使用这些有限的常量
枚举类举例
简单定义一个枚举类型,如下:
public enum Week {
MONDAY,
TUESDAY,
WEDNESDAY,
THURSDAY,
FRIDAY,
SATURDAY,
SUNDAY;
}
枚举类型的常用方法
可以使用枚举类型的values()静态方法返回枚举类型中的所有枚举值
使用枚举常量的name()方法返回枚举常量的名称
使用枚举常量的ordinal()方法返回枚举常量的序数(常量在枚举声明中的位置,从0开始)。示例代码如下:
public static void main(String[] args) {
//获取枚举类型中的全部枚举值
Week[] days = Week.values();
for(Week day : days) {
//返回枚举常量的名称
String name = day.name();
//返回枚举常量的序数(常量在枚举声明中的位置,从0开始)
int ordinal = day.ordinal();
String toString = day.toString();
Class declaringClass = day.getDeclaringClass();
Class superClass = declaringClass.getSuperclass();
System.out.println(
"Name: " + name
+ "n"
+ "Ordinal: " + ordinal
+ "n"
+ "ToString: " + toString
+ "n"
+ "DeclaringClass: " + declaringClass
+ "n"
+ "SuperClass: " + superClass
+ "n"
);
}
}
输出结果如下:
Name: MONDAY
Ordinal: 0
ToString: MONDAY
DeclaringClass: class myEnum.Week
SuperClass: class java.lang.Enum
Name: TUESDAY
Ordinal: 1
ToString: TUESDAY
DeclaringClass: class myEnum.Week
SuperClass: class java.lang.Enum
Name: WEDNESDAY
Ordinal: 2
ToString: WEDNESDAY
DeclaringClass: class myEnum.Week
SuperClass: class java.lang.Enum
Name: THURSDAY
Ordinal: 3
ToString: THURSDAY
DeclaringClass: class myEnum.Week
SuperClass: class java.lang.Enum
Name: FRIDAY
Ordinal: 4
ToString: FRIDAY
DeclaringClass: class myEnum.Week
SuperClass: class java.lang.Enum
Name: SATURDAY
Ordinal: 5
ToString: SATURDAY
DeclaringClass: class myEnum.Week
SuperClass: class java.lang.Enum
Name: SUNDAY
Ordinal: 6
ToString: SUNDAY
DeclaringClass: class myEnum.Week
SuperClass: class java.lang.Enum
比较枚举常量
判断两个枚举类型常量的值是否相等,可以直接使用“==”,而不用equals()方法。
原因:
枚举有着严格的实例化控制,在枚举中final clone方法确保枚举常量从不会被克隆,而且序列化机制会确保从不会因为反序列化而创造复制的实例。枚举类型的反射实例化也是被禁止的。
比较两个枚举类型常量的值的大小,可以使用compareTo()方法。
public static void main(String[] args) {
Week mon = Week.MONDAY;
Week tues = Week.TUESDAY;
Week wed = Week.WEDNESDAY;
//比较枚举常量,实际上是比较它们序数的大小
System.out.println(mon.compareTo(tues));
System.out.println(tues.compareTo(wed));
System.out.println(wed.compareTo(mon));
}
输出结果如下:
-1
-1
2
实际上,比较两个枚举常量的大小,就是比较它们序数ordinal的大小。在JDK1.6的Enum源码中compareTo()方法如下:
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;
}
创建枚举常量
创建枚举常量主要有三种方法:
- 直接利用枚举类型创建枚举常量、
- 使用Enum的valueOf()静态方法创建枚举常量、
- 使用枚举类型的valueOf()静态方法创建枚举常量。
//直接创建枚举常量
Week mon = Week.MONDAY;
//使用Enum的valueOf()静态方法创建枚举常量
Week tues = Enum.valueOf(Week.class, "TUESDAY");
//使用枚举类型的valueOf()静态方法创建枚举常量
Week wed = Week.valueOf("WEDNESDAY");
定义高级的枚举类型
根据需要,可以在枚举类型中添加构造器、方法和字段,还可以让枚举类型继承接口。
定义接口IWeek,如下:
public interface IWeek {
public void println();
}
定义高级的枚举类型AdvancedWeek,拥有自己的构造器、方法和字段,并实现IWeek接口。
public enum AdvancedWeek implements IWeek{
MONDAY("星期一", "Mon."),
TUESDAY("星期二", "Tues."),
WEDNESDAY("星期三", "Wed."),
THURSDAY("星期四", "Thurs."),
FRIDAY("星期五", "Fri."),
SATURDAY("星期六", "Sat."),
SUNDAY("星期日", "Sun.");
private String nameCn;
private String abbreviation;
//构造方法只能为private,定义其他类型会报错,不写也是private
private AdvancedWeek() {}
private AdvancedWeek(String nameCn, String abbreviation) {
this.setNameCn(nameCn);
this.setAbbreviation(abbreviation);
}
public String getNameCn() {
return nameCn;
}
public void setNameCn(String nameCn) {
this.nameCn = nameCn;
}
public String getAbbreviation() {
return abbreviation;
}
public void setAbbreviation(String abbreviation) {
this.abbreviation = abbreviation;
}
public void println() {
System.out.println(this.ordinal() + " - " + this.name() + " - " + this.getAbbreviation() + " - " + this.getNameCn());
}
}
需要注意的是,枚举类型的构造方法只能为private。
测试AdvancedWeek,如下:
AdvancedWeek[] days = AdvancedWeek.values();
for(AdvancedWeek day : days) {
day.println();
}
}
输出结果为:
0 - MONDAY - Mon. - 星期一
1 - TUESDAY - Tues. - 星期二
2 - WEDNESDAY - Wed. - 星期三
3 - THURSDAY - Thurs. - 星期四
4 - FRIDAY - Fri. - 星期五
5 - SATURDAY - Sat. - 星期六
6 - SUNDAY - Sun. - 星期日
enum类型的name
name()方法。这个方法会返回一个枚举值的字面量
public enum AnimalEnum {
DOG("狗"),
CAT("猫");
private String message;
……
AnimalEnum.DOG.name() 就是字符串类型的DOG