1、前置知识
1、枚举类是一个特殊的类,,它一样有自己的成员变量、方法,可以实现一个或多个接口,也可以定义自己的构造器。 2、一个 java 源文件最多只能定义一个 public 访问权限的 枚举类。且该 java 源文件也必须和该枚举的类名相同 3、枚举类默认继承了 java.lang.Enum 类,而不是 Object 类,所以枚举类不能显示继承其他父类。其中 java.lang.Enum 类实现了 java.lang.Serializable 和 java.lang.Comparable 两个接口。 4、使用 enum 定义、非抽象的枚举类会默认使用 final 修饰 5、枚举类的构造器只能用 private 访问控制符,因为子类构造器总要调用父类构造器一次,所以枚举类不能派生子类 6、在枚举类中列出枚举值时,实际上就是调用构造器创建枚举类对象。只是这里无需使用 new 关键字。也无需显示调用 构造器。前面列出枚举值时无需传入参数(调用无参的构造方法),也可以传入参数(有参的构造方法) 7、枚举类的所有实例必须在枚举类的第一行显示列出,否则这个枚举类永远不能产生实例。列出这些实例时系统会自动 添加 public static final 修饰,无需自动添加
package main.enumkey;
public enum SeasonEnum {
FALL,
SPRING,
SUMMER,
WINTER("冬天");
public String season;
SeasonEnum() {
}
SeasonEnum(String season) {
this.season = season;
}
public String getSeason() {
return season;
}
public void setSeason() {
switch (this) {
case SPRING:
this.season = "春天";
break;
case SUMMER:
this.season = "夏天";
break;
case FALL:
this.season = "秋天";
break;
}
}
}
2、测试
package main.enumkey;
public class EnumTest {
public static void main(String[] args) {
test1();
test2();
test3();
}
static void test1() {
System.out.println(SeasonEnum.WINTER.getSeason());
System.out.println(SeasonEnum.SPRING.getSeason());
System.out.println("-------------------test1-END------------------");
}
static void test2() {
for (SeasonEnum seasonEnum : SeasonEnum.values()) {
System.out.println(seasonEnum);
System.out.println(seasonEnum.valueOf(SeasonEnum.class, seasonEnum.name()));
System.out.println(seasonEnum.compareTo(SeasonEnum.SPRING));
System.out.println(seasonEnum.ordinal());
System.out.println(seasonEnum.toString());
System.out.println("===================");
}
System.out.println("-------------------test2-END------------------");
}
static void test3() {
SeasonEnum seasonEnum = Enum.valueOf(SeasonEnum.class, "SPRING");
SeasonEnum seasonEnum1 = Enum.valueOf(SeasonEnum.class, "SPRING");
System.out.println("修改前: " + seasonEnum.season);
seasonEnum.season = "春秋季";
seasonEnum1.season = "冬夏季";
System.out.println("seasonEnum-被修改后: " + seasonEnum.season);
System.out.println("seasonEnum1-被修改后: " + seasonEnum1.season);
System.out.println("-------------------test3-END------------------");
}
}
test1 test2 test3
3、改进枚举类
package main.enumkey;
public enum SeasonEnum1 {
FALL("秋天"),
SPRING("春天"),
SUMMER("夏天"),
WINTER("冬天");
public final String season;
SeasonEnum1(String season) {
this.season = season;
}
public String getSeason() {
return season;
}
}
enum test {
}
4、实现接口的枚举类
GanderDec接口
public interface GanderDec {
void ganderInfo();
}
Gander枚举类实现GanderDec接口
package main.enumkey;
public enum Gander implements GanderDec {
MALE("男"), FEMALE("女");
private final String gander;
Gander(String gander) {
this.gander = gander;
}
@Override
public void ganderInfo() {
System.out.println("我的性别是:" + gander);
}
}
测试
static void test4() {
System.out.println(Gander.MALE);
System.out.println(Gander.FEMALE);
Gander.MALE.ganderInfo();
Gander.FEMALE.ganderInfo();
System.out.println("-------------------test4-END------------------");
}
如果由枚举类来实现接口里的方法,则每个枚举值在调用该方法 时都有相同的行为方式(因为方法体完全一样)。如果需要每个枚举 值在调用该方法时呈现出不同的行为方式,则可以让每个枚举值分别 来实现该方法,每个枚举值提供不同的实现方式,从而让不同的枚举 值调用该方法时具有不同的行为方式
第二种重写方法(分别重写)
package main.enumkey;
public enum Gander implements GanderDec {
MALE("男") {
@Override
public void ganderInfo() {
System.out.println("黑马王子");
}
},
FEMALE("女") {
@Override
public void ganderInfo() {
System.out.println("白雪公主");
}
};
private final String gander;
Gander(String gander) {
this.gander = gander;
}
}
当创建MALE和FEMALE两个枚举值时,后面又紧跟了一对花括号,这对花括号里包含了一个 ganderInfo()方法定义。如果读者还记得匿名内部类语法的话,则可能对这 样的语法有点印象了,花括号部分实际上就是一个类体部分,在这种 情况下,当创建MALE、FEMALE枚举值时,并不是直接创建Gender枚举 类的实例,而是相当于创建Gender的匿名子类的实例。因为括 号部分实际上是匿名内部类的类体部分,所以这个部分的代码语法与匿名内部类语法大致相似,只是它依然是枚举类的匿名内 部子类。
枚举类不是用final修饰了吗?怎么还能派生子类呢?
并不是所有的枚举类都使用了final修饰!非抽象的枚举类才默 认使用final修饰。对于一个抽象的枚举类而言——只要它包含了抽 象方法,它就是抽象枚举类,系统会默认使用abstract修饰,而不是 使用final修饰。
拓展:
抽象方法: java中的抽象方法就是以abstract修饰的方法,这种方法只声明返回的数据类型、方法名称和所需的参数,没有方法体,也就是说抽象方法只需要声明而不需要实现。 抽象方法与抽象类: 当一个方法为抽象方法时,意味着这个方法应该被子类的方法所重写,否则其子类的该方法仍然是abstract的,这个子类由于继承父类,拥有抽象方法,因此它也是抽象类,即声明为abstract。abstract抽象类不能用new实例化对象,abstract方法只允许声明不能实现。如果一个类中含有abstract方法,那么这个类必须用abstract来修饰,当然abstract类也可以没有abstract方法。 一个抽象类里面没有一个抽象方法可用来禁止产生这种类的对象。(摘自百度文库:java抽象类和方法,作者:余书慧先生) 抽象方法与接口: 在interface中所有的方法都是public abstract的,即使你没有申明它是public abstract的。在interface中所有的数据成员都是public static final的,即使你没有申明.但不能是blank final 在编译时候确定的。在Java,interface的地位和class是一样的。实现interface的类,其interface中所有的方法必须被“实现”,否则这个类成为一个抽象类。Interface可以从多个interface得到继承,但是不能继承类。一个类可以实现多个interface
编 译 上 面 的 程 序 , 可 以 看 到 生 成 了 Gender.class 、 Gender$1.class和Gender$2.class三个文件,这样的三个class文件正 好证明了上面的结论:MALE和FEMALE实际上是Gender匿名子类的实 例,而不是Gender类的实例。当调用MALE和FEMALE两个枚举值的方法 时,就会看到两个枚举值的方法表现不同的行为方式
上边是从实现某个接口,从而包含抽象方法,接下来定义一个包含抽象方法的枚举类
package main.enumkey;
public enum Operation {
PLUS {
public double eval(double x, double y) {
return x + y;
}
},
MINUS {
public double eval(double x, double y) {
return x - y;
}
},
TIMES {
public double eval(double x, double y) {
return x * y;
}
},
DIVIDE {
public double eval(double x, double y) {
return x / y;
}
};
public abstract double eval(double x, double y);
public static void main(String[] args) {
System.out.println(Operation.PLUS.eval(2, 3));
System.out.println(Operation.MINUS.eval(2, 3));
System.out.println(Operation.TIMES.eval(2, 3));
System.out.println(Operation.DIVIDE.eval(2, 3));
}
}
编译上面程序会生成5个class文件,其实Operation对应一个 class文件,它的4个匿名内部子类分别各对应一个class文件。 枚举类里定义抽象方法时不能使用abstract关键字将枚举类定义成抽象类(因为系统自动会为它添加abstract关键字),但因为枚举 类需要显式创建枚举值,而不是作为父类,所以定义每个枚举值时必 须为抽象方法提供实现,否则将出现编译错误。
|