枚举类
Tags: enum
枚举类入门
枚举类是一个特殊的类, 它一样可以有自己的属性和方法, 可以实现一个或者多个接口, 也可以定义自己的构造器。
枚举类与普通类有以下区别:
使用enum定义的枚举类默认继承
java.lang.Enum
这个类, 而不像普通类一样默认继承java.lang.Object
类。 其中java.lang.Enum
这个类实现了java.lang.Serializable
和java.lang.Comparable
两个接口。枚举类的构造方法只能用
private
修饰, 如果没有modifier, 则默认为private
。枚举类的所有势力都必须在枚举类中显式列出, 否则这个枚举类都将永远不能产生实例。列出实例时, 系统自动添加
public static final
修饰,无需显式添加。所有枚举类都提供给了一个
values()
方法, 返回该枚举类的所有实例
例:
“`
public enum Season {
SPRING, SUMMER, AUTUMN, WINTER;
}
“`
以上代码等同于:
“`
public enum Season {
public static final SPRING;
public static final SUMMER;
public static final AUTUMN;
public static final WINTER;
private Season() {
}
}
“`
测试:
“`
public class TestSeason {
public static void main(String[] args) {
for (Season s : Season.values()) {
System.out.println(s);
}
}
}
“`
输出:
SPRING
SUMMER
AUTUMN
WINTER
枚举类的属性、方法、构造方法
枚举类也是一种类, 不过是一种比较挺特殊的类,但是一样可以有属性和方法。
先看一个简单的例子:
public enum Gender {
MALE, FEMALE;
private String name;
public void setName(String name) {
switch (this) {
case MALE :
if (name.equals("man")) {
this.name = name;
} else {
System.out.println(name + " is not correct.")
return;
}
break;
case FEMALE :
if (name.equals("woman")) {
this.name = name;
} else {
System.out.println(name + " is not correct.")
return;
}
break;
}
}
}
上面的代码可以是可以, 但是不是最优,首先它略显啰嗦累赘。其次,枚举类通常应该设计成不可变类, 也就是说它的属性不应该允许改变, 这样会更加安全而且更加简洁。 因此, 应该将枚举类的属性都使用private final
修饰。
因为我们将所有属性都用了final
来修饰, 所以必须在构造器里为这些属性制定初始值,也就是说为枚举类显式的定义带参数的构造方法。一旦为枚举类显式定义了带参数的构造方法, 则列出枚举值时也必须对应的传入参数(可以把枚举类里列出枚举值的过程看成创建一个该枚举类对象的过程,但无需使用new
这个关键字, 也无需显式的调用构造器。创建对象调用该枚举类带参数的构造方法,所以在列出枚举值时也要相应的传入参数 )
所以把上面的代码改成:
public enum Gender {
MALE("man"),
FEMALE("woman");
private final String name;
private Gender(String name) {
this.name = name;
}
}
实现接口的枚举类
枚举类也可以实现一个或者多个接口, 与普通类一样, 枚举类实现接口时, 也必须实现接口所包含的所有方法。
如果由枚举类来实现接口里的方法, 那么每个枚举值在调用该方法的时候, 都会有相同的行为方式(因为方法体完全一样)。如果需要每个枚举值在调用该方法时呈现出不同的行为方式, 可以让每个枚举值分别来实现该方法, 每个枚举值提供不同的行为方式(每个枚举值对接口里的方法有不同的重写)。
例:让上面的Gender
类实现IGender
接口, 并且让MALE
、FEMALE
对接口里的方法进行不同的重写
interface IGender {
public void info();
}
public enum Gender implements IGender {
MALE("man") {
public void info() {
System.out.println("This is a man");
}
},
FEMALE("woman") {
public void info() {
System.out.println("This is a woman");
}
};
private Gender(String name) {
this.name = name;
}
}
测试:
“`
public class TestGender {
public static void main(String[] args) {
Gender.MALE.info();
Gender.FEMALE.info();
}
}
“`
结果:
This is a man
This is a woman
上面的代码乍看有点奇怪, 但是仔细看看, 发现它好像匿名内部类的写法。在这种情况下, 当创建MALE、FEMALE枚举值时, 并不是直接创建Gender枚举类的实例,而是相当于创建Gender的匿名子类的实例。编译上面的程序, 可以看到生成了Gender.class、Gender 1.class、Gender 2.class三个文件,证明了上面的结论。
包含抽象方法的枚举类
假设有一个Calculator
枚举类,它的四个枚举值PLUS
,MINUS
,TIMES
,DIVIDE
分别代表加减乘除。
public enum Operator {
`PLUS`,`MINUS`,`TIMES`,`DIVIDE`;
double calculate(double x, double y) {
double calculate(double x, double y) {
switch (this) {
case PLUS:
return x + y;
case MINUS:
return x - y;
case TIMES:
return x * y;
case DIVIDE:
return x / y;
default:
return 0;
}
}
}
}
上面代码中default
这段代码完全没有必要写。四个枚举值对calculate(double x, double y)
这个方法都有不同的实现, 可以考虑写成这个枚举类实现某个接口, 接口里的方法是calculate(double x, double y)
interface IOperator {
public double calculate(double x, double y);
}
public enum Operator implements IOperator {
PLUS {
public double calculate(double x, double y) {
return x + y;
}
},
MINUS {
public double calculate(double x, double y) {
return x - y;
}
},
TIMES {
public double calculate(double x, double y) {
return x * y;
}
},
DIVIDE{
public double calculate(double x, double y) {
return x / y;
}
};
}
也可以直接在Operator
里直接定义一个calculate的抽象方法 :
public enum Operator implements IOperator {
PLUS {
public double calculate(double x, double y) {
return x + y;
}
},
MINUS {
public double calculate(double x, double y) {
return x - y;
}
},
TIMES {
public double calculate(double x, double y) {
return x * y;
}
},
DIVIDE{
public double calculate(double x, double y) {
return x / y;
}
};
public abstract double calculate(double x, double y);
}
学习抽象类的时候,如果方法被生命为abstract, 那么类必须也要声明为abstract,但是在枚举类里定义抽象方法时无需显式的使用abstract
关键字将枚举类定义为抽象类。这是因为:枚举类需要显式的创建枚举值, 而不是作为父类, 所以定义每个枚举值时必须为抽象方法提供实现, 否则编译出错