枚举类简要介绍
枚举是Java1.5引入的新特性,通过关键字enum来定义枚举类,enum关键字和class、interface、@interface(注解)的地位是相同的。枚举类是一种特殊类,它和普通类一样可以使用构造器、定义成员变量和方法,也能实现一个或多个接口。但枚举类不能继承其他类,因为枚举类默认继承java.lang.Enum类(注:Enum是抽象类),Java是单继承,所以不允许。
枚举类的特点
- 枚举类的构造器默认被private修饰,如果显式指定,也只能用private来修饰,不然会报错。
- 枚举类的实例必须在第一行显式列出,不然无法生成枚举实例,枚举实例就是枚举值。
- 枚举值默认被public final static修饰。枚举类默认被final修饰,无法被继承。
- 枚举值可以看作静态常量对象,除了拥有常量的特性外,还和对象一样可以调用方法、成员变量。
- 和普通类比起来,枚举类对象数量在第一行就被固定下来了,不能随意创建。
public enum Color {
RED, GREEN, BLUE;
}
//编译上面枚举类后,会生成对应的字节码文件:Color.class
通过上面代码,可以看出编译后的枚举类和普通类大致差不多,只是用法稍有不同。我们再来看一下,列出枚举值时无需指定类型,平时定义常量时是要指定类型的,在上面关于枚举类的特点中,说过枚举值就是枚举类对象,所以列出枚举值就是在创建对象,这会使用到构造器,这里的构造器是默认的,这时候看一下父类代码:
//父类Enum的构造器
protected Enum(String name, int ordinal) {
this.name = name;
this.ordinal = ordinal;
}
每创建一个枚举值就会调用上述父类构造器,生成对应的enum类型静态常量,并且按照顺序设置值,初始值为0。总之,使用枚举类时,只需将枚举值看作枚举类的对象来用就行。
枚举类的用法
boolean | equals(Object other) 当指定对象等于此枚举常量时,返回 true。 | |
protected void | finalize() 枚举类不能有 finalize 方法。 | |
Class<E> | getDeclaringClass() 返回与此枚举常量的枚举类型相对应的 Class 对象。 | |
int | hashCode() 返回枚举常量的哈希码。 | |
String | name() 返回此枚举常量的名称,在其枚举声明中对其进行声明。 | |
int | ordinal() 返回枚举常量的序数(它在枚举声明中的位置,其中初始常量序数为零)。 | |
String | toString() 返回枚举常量的名称,它包含在声明中。 | |
static
| valueOf(Class<T> enumType,String name) 返回带指定名称的指定枚举类型的枚举常量。 |
查看枚举值的序数
System.out.println(Color.RED.ordinal());
System.out.println(Color.GREEN.ordinal());
System.out.println(Color.BLUE.ordinal());
//输出序数
0
1
2
这里的序数就是定义枚举值时自动为其生成的,理论上来说可以看作是它们的初始值,但提供的数据较少,所以要为枚举值附加更多属性时,可以创建成员变量,使用构造器来赋值。其他方法的话都比较简单,在此省略示例代码。
枚举类中定义变量和方法
public enum Color {
RED, GREEN, BLUE; //列出枚举值, 枚举类实例
//定义实例变量和静态变量
private int a = 10;
private static int b = 100;
//定义方法
public int getA() {
return this.a;
}
public static void main(String[] args) {
Color.RED.a = 20;
Color.RED.b = 101;
Color.GREEN.a = 30;
Color.GREEN.b = 102;
System.out.println("RED.a = " + Color.RED.getA());
System.out.println("GREEN.a = " + Color.GREEN.getA());
//RED.a = 20
//GREEN.a = 30
}
}
上面实例中,使用枚举值可以调用成员变量、实例方法,静态属性也是共享的,和普通类对象用法差不多。如果只是这样赋值的话,会显得麻烦且逻辑不清晰,所以采用用构造器来给给对象赋值的用法来给枚举值赋值,实例如下:
RED(15), GREEN(30), BLUE(45); //为枚举值的实例变量赋值
//定义实例变量
private int a = 10;
//枚举类的构造器
private Color(int a) {
this.a = a;
}
//测试
public static void main(String[] args) {
System.out.println(Color.RED.a);
System.out.println(Color.GREEN.a);
System.out.println(Color.BLUE.a);
}
上面只是定义了3个枚举值,每次获取值时就显得很麻烦了,而且重复代码太多,这时就可以使用values()方法返回枚举类所有实例,转成枚举数组。但在Enum源码中并没有该方法,这个问题我也不清楚.....,改进后如下:
//使用values()来循环获取属性值。但获取属性值最好是用getXxx()来完成
public static void main(String[] args) {
for(Color c : Color.values()) {
System.out.println(c.a);
}
}
枚举类应用场景
1.最常用到的当属常量,例如定义各类状态时,使用枚举类可以把相关联的常量放在一个枚举类中,并能根据需求来增加属性和方法。
public enum Sex {
MAN("男") , MALE("女");
private String sex;
private Sex(String sex) {
this.sex = sex;
}
//重写toString(),返回枚举值的sex属性
@Override
public String toString() {
return this.sex;
}
public static void main(String[] args) {
System.out.println(Sex.MAN.toString());
System.out.println(Sex.MALE.toString());
//输出结果
男
女
}
相较于常量而言,枚举类可以另加灵活化,还能对常量进行统一管理。
2.可以在switch语句使用枚举类,switch可以自动检查枚举值是否属于传入的枚举类
public static void main(String[] args) {
//得到枚举数组
SeasonEnum[] se = SeasonEnum.values();
//随机获得其中一个枚举
SeasonEnum rand = Test.getRandomEnum(se);
switch(rand) {
case SPRING:
System.out.println(rand + ", 是" + rand.getSeason());
break;
case SUMMER:
System.out.println(rand + ", 是" + rand.getSeason());
break;
case AUTUMN:
System.out.println(rand + ", 是" + rand.getSeason());
break;
case WINTER:
System.out.println(rand + ", 是" + rand.getSeason());
break;
}
}
/** 根据指定的枚举数组来随机获得其中一个枚举 */
public static <T extends Enum> T getRandomEnum(T[] enumArr) {
int index = (int)(Math.random() * enumArr.length); //生成的下标在枚举数组长度范围之内
T rs = enumArr[index];
return rs;
}
3.枚举类可以在接口中定义,也可以定义在类里面,访问权限的使用和内部类一样,等于使用内部类来维护一些常量的使用。
//能定义在接口中
interface testEnum{
enum State{
ON, OFF;
}
}
//定义成内部枚举类
public class Test {
enum State{
ON, OFF;
}
}
4.除了以上这些,枚举还能应用于集合:EnumSet和EnumMap,Set的底层是采用Map存储key值来实现的,所以EnumSet的值和EnumMap的key一样是需要枚举类型,但Map的value类型就随意了。 由于枚举集合基本用不了,所以没有给出例子,如果有需要,可以自行查询相关资料。