枚举类 ——Java5
【基础知识】
1,定义枚举类——关键字 enum (地位与class、interface相同)。
2,枚举类是一个特殊的类,可以有成员变量、方法,实现一个或多个接口,定义自己的构造器。
3,一个Java源文件中最多只能定义一个public访问权限的枚举类,且该Java源文件也必须和该枚举类的类名相同。
【枚举类与普通类的区别】
1,使用enum定义的枚举类默认继承了java.lang.Enum类,不是默认继承Object类。因此枚举类不能显式继承其它父类。
其中,java.lang.Enum类实现类java.lang.Serializable和java.lang.Comparable两个接口。
2,使用enum定义、非抽象的枚举类默认会使用final修饰,因此枚举类不能派生子类。
3,枚举类的构造器只能使用private访问控制符,省略系统自动添加。
4,枚举类的所有实例必须在枚举类第一行显式列出,否则这个枚举类永远都不能产生实例。
列出这些实例时,系统自动添加public static final修饰。
5,调用枚举类实例:
类名.实例名
如:SeasonEnum.SPRING
6,产生实例可以用valueOf方法,如:Gender g = Enum.valueOf(Gender.class, "FEMALE");
枚举类的实例只能是枚举值,不是随意通过new来创建对象。
例子——定义枚举类:
public enum SeasonEnum
{
//在第一行列出4个枚举实例
SPRING, SUMMER, FALL, WINTER;
}
【方法】
* 默认提供了values()方法,返回枚举类所有实例。 如:
//打印SeasonEnum的所有实例
for(SeasonEnum s : SeasonEnum.values())
{
System.out.println(s); //实际调用了toString方法
}
* public final int compareTo(E o):与指定枚举对象比较顺序,同一个枚举实例只能与相同类型的枚举实例进行比较。
如果该枚举对象位于指定枚举对象之后,返回正整数;之前,返回负整数;否则,返回0。
* public final String name():返回此枚举实例的名称,这个名称就是定义枚举类时列出的所有枚举值之一。
应优先考虑toString方法,因为toString返回更友好的名称。
* public final int ordinal():返回枚举值在枚举类中的索引值(枚举值在枚举声明中的位置,第一个枚举值的索引值为0)。
* public String toString():返回枚举常量名称,与默认与name()方法相似,只是该方法可以被重写。
* public static <T extends Enum<T>> T valueOf(Class<T> enumType, String name):
静态方法,返回指定枚举类中指定名称的枚举值。 名称必须与在枚举类中声明枚举值时所用的标识符完全匹配,不允许使用额外的空白字符。
【实例——枚举类的应用及改进】
enum Gender
{
MALE, FEMALE;
private String name;
public void setName(String name) {
switch (this) {
case MALE:
if(name.equals("男")) {
this.name = name;
} else {
System.out.println("参数错误");
return;
}
break;
case FEMALE:
if (name.equals("女")) {
this.name = name;
} else {
System.out.println("参数错误");
return;
}
break;
}
}
public String getName() {
return this.name;
}
}
public class Demo
{
public static void main(String[] args) {
Gender g = Enum.valueOf(Gender.class, "FEMALE");
g.setName("女");
System.out.println(g + "代表" + g.getName());
//设置name值错误会出现参数错误提示
g.setName("男");
System.out.println(g + "代表" + g.getName());
}
}
//以上的做法并不太好,因为枚举类应该设置为一个不可变类,它的成员变量不应该允许改变。
//建议将枚举成员变量都用private final修饰。
//因为成员变量都被私有化,因此必须在构造器中为这些成员变量指定初始值(或在定义成员变量时指定默认值,或在初始化块中指定初始值)。
enum Gender_improve
{
MALE("男"), FEMALE("女");
//先当于:
//public static final Gender MALE = new Gender("男");
//public static final Gender FEMALE = new Gender("女");
private final String name;
private Gender_improve(String name) {
this.name = name;
}
public String getName() {
return this.name;
}
}
【实现接口的枚举类】
1,枚举类实现接口的方法与普通类完全一样。
2,如果由枚举类实现接口里的方法,则每个枚举值在调用该方法时都会有相同的行为方式(因为方法体完全一样)。
3,如果需要每个枚举值在调用该方法时呈现出不同的行为,则可以让每个枚举值分别实现该方法。
例子:
interface GenderDesc
{
void info();
}
enum Gender implements GenderDesc
{
MALE("男") {
public void info() {
System.out.println("这个枚举值代表男性");
}
}, //注意逗号
FEMALE("女") {
public void info() {
System.out.println("这个枚举值代表女性");
}
}; //注意分号
private final String name;
private Gender(String name) {
this.name = name;
}
public String getName() {
return this.name;
}
}
4,当创建MALE和FEMALE枚举值时,不是直接创建Gender枚举类的实例,而实现当与创建Gender的匿名内部子类的实例。
5,编译以上文件,发现生成了Gender.class、Gender$1.class、Gender$2.class三个文件。
这验证了4结论,MALE和FEMALE实际上是Gender匿名内部子类的实例。
【抽象枚举类——有子类的抽象类】
1,并不是所有的枚举类都使用了final修饰,非抽象的枚举类才默认使用final修饰。
2,只要枚举类包含了抽象方法,它就是抽象枚举类,系统默认用abstract修饰,而不是final。
注意,不能用abstract关键字定义抽象枚举类,因为系统会自动添加。
3,因为枚举类需要显式创建枚举值,而不是作为父类,所以定义每个枚举值时必须为抽象方法提供实现,否则会编译错误。