在某些情况下,一个类的对象是有限而且固定的,比如季节类,它只有4个对象,这种实例有限而且固定的类,在Java里被称为枚举类。
枚举类是一种特殊的类,它一样可以有自己的成员变量、方法,可以实现一个或者多个接口,也可以定义自己的构造器。用enum关键字定义枚举类。上面的季节枚举类可以定义如下:
public enum SeasonEnum { SPRING, SUMMER, FALL, WINTER }
枚举类与普通类的区别如下:
1、枚举类默认继承java.lang.Enum类,而不是默认继承Object类,因此枚举类不能显式继承其他类。
2、枚举类都是final的,不能被继承。
3、枚举类的构造器只能使用private访问控制符。如果省略了访问控制符,则默认使用private修饰;如果非要指定访问控制符,则只能指定private,当然这时IDE会提醒private修饰符是多余的。
4、枚举类的所有实例必须在第一行显式列出(或者前几行,如果换行的话),枚举值之间以英文逗号分隔,最后面加分号,否则这个枚举类永远都不能产生实例,且我们不能对这些实例添加修饰符。
我们可以通过枚举类名打点的方式获取枚举值,如SeasonEnum spring = SeasonEnum.SPRING;。此外,枚举类默认提供了一个values()静态方法,这个返回所有枚举类实例组成的数组。
Enum实现了Comparable接口和Serializable接口,方法有:
1、int compareTo(E e):与另一个Enum实例比较。如SeasonEnum.SPRING.compareTo(SeasonEnum.SUMMER),zhidezhuyi返回什么呢?或者说枚举值怎么比呢?用什么属性比呢?答案是根据定义枚举类时声明的实例的索引,第一个枚举值索引为0,之后逐渐加1。
2、boolean equals(Object o):注意,这个方法不是继承自Object类的。Enum类并没有继承Object类。值得注意的是,这个equals()方法是final的,也就是说,我们自定义枚举类是不能重写这个方法的。
3、String toString():这个方法也不是继承自Object类,而是自有的。返回枚举值的名称。如SeasonEnum.SPRING.toString()返回"SPRING"字符串。
4、int ordinal():返回枚举值的索引。如上所述,第一个枚举值的索引是0,第二个枚举值的索引是1。。。
5、Enum<T> valueOf(Class<T> enumType, String name)静态方法:通过这个方法可以获取一个枚举值。如SeasonEnum spring = Enum.valueOf(SeasonEnum.class, "SPRING");
枚举类的成员变量、方法和构造器
枚举类也可以定义成员变量、方法和构造器。枚举类的成员变量的值不应该允许变化,因此最好将成员变量都用private final修饰。那么在什么时候赋值呢?一种方式是在声明成员变量的时候赋值或者在初始代码块中赋值,把成员变量当成一个常量,如private final String name = "张三";,那么所有枚举值的这个成员变量的值都一样,都是"张三"字符串。另一种方式是在构造器中为成员变量赋值。如
SeasonEnum(String name) { this.name = name; }
一旦为枚举值显式定义了带参数的构造器,则列出枚举值时必须对应地传入参数。如下:
public enum SeasonEnum { SPRING("spring"), SUMMER("summer"), FALL("fall"), WINTER("winter"); private final String name; SeasonEnum(String name) { this.name = name; } public String getName() { return name; } }
在枚举类中列出枚举值时,实际上就是调用构造器创建枚举类对象,只是不用使用new关键字而已。
实现接口的枚举类
可以像普通类实现接口一样,重写接口的方法。假如SeasonInterface接口有一个void info()方法,SeasonEnum枚举实现了SeasonInterface,如下:
public enum SeasonEnum implements SeasonInterface { SPRING("spring"), SUMMER("summer"), FALL("fall"), WINTER("winter"); private final String name; SeasonEnum(String name) { this.name = name; } public String getName() { return name; } @Override public void info() { System.out.println(this.getName()); if (this == SPRING) { System.out.println(1); } else if (this == SUMMER) { System.out.println(2); } else if (this == FALL) { System.out.println(3); } else if (this == WINTER) { System.out.println(4); } } }
此外,枚举类重写接口方法还有自己独特的一种形式,即在每个枚举值后面花括号包裹重写的方法,如下:
public enum SeasonEnum implements SeasonInterface { SPRING("spring") { @Override public void info() { System.out.println(1); } }, SUMMER("summer") { @Override public void info() { System.out.println(2); } }, FALL("fall") { @Override public void info() { System.out.println(3); } }, WINTER("winter") { @Override public void info() { System.out.println(4); } }; private final String name; SeasonEnum(String name) { this.name = name; } public String getName() { return name; } }
包含抽象方法的枚举类
假设SeasonEnum有一个抽象方法void cool()。这里想一下,枚举类是不能被继承的,那么这个cool()方法由谁去实现呢??答案是由枚举类自己去实现或者更准确一点说,是由枚举类的匿名子类去实现。如下:
public enum SeasonEnum implements SeasonInterface { SPRING("spring") { @Override public void cool() { } @Override public void info() { System.out.println(1); } }, SUMMER("summer") { @Override public void cool() { } @Override public void info() { System.out.println(2); } }, FALL("fall") { @Override public void cool() { } @Override public void info() { System.out.println(3); } }, WINTER("winter") { @Override public void cool() { } @Override public void info() { System.out.println(4); } }; private final String name; SeasonEnum(String name) { this.name = name; } public String getName() { return name; } public abstract void cool(); }