一、什么是枚举类
在JDK1.5之前,Java有两种方式定义新类型:类和接口。对于大部分面向对象编程来说,这两种方法似乎够了。但是在一些特殊情况下,这些方法就不是和合适。例如:想定义一个Color类,它只能够有Red, Blue, Black3种值,其他任何值都是非法的,那么在虽然在JDK1.5之前可以构造这样的代码,但是要做很多的工作,就可能会带来各种不安全的问题。而JDK1.5之后引入的枚举类型(Enum)就能够避免这些问题。
枚举类本质上还是一个类,每一个枚举类都继承了抽象类Enum。
二、JDK1.5之前实现枚举功能的类
1)通过private将其构造方法私有化,使得在类的外部无法实例化该类
2)该类所有可能的实例都使用public static final 来修饰的属性保存起来
3)提供静态方法,允许通过特定的参数来获取与之匹配的实例
示例代码:
package com.wbf.enum1;
//JDK1.5之前,实现枚举功能的类
class Color {
public static final Color RED = new Color("红色");
public static final Color BLUE = new Color("蓝色");
public static final Color BLACK = new Color("黑色");
private String name;
private Color(String n){
this.name = n;
}
public void setName(String name){
this.name = name;
}
public String getName(){
return this.name;
}
public static Color getInstance(Integer colorNum){
switch(colorNum){
case 1 :
return RED;
case 2 :
return BLUE;
case 3 :
return BLACK;
default :
return null;
}
}
}
public class EnumDemo1 {
public static void main(String[] args) {
Color c = Color.getInstance(1);
System.out.println(c.getName());
c = Color.getInstance(2);
System.out.println(c.getName());
}
}
三、使用enum关键字来定义一个枚举类,实现如下操作
1)获取枚举的指定内容
2)遍历枚举常量
3)switch和枚举一起使用
代码实例如下:
package com.wbf.enum2;
//使用关键字enum来定义枚举类
enum Color{
RED, BLUE, BLACK;
}
public class EnumDemo2 {
public static void main(String[] args) {
//枚举.variable来取出枚举指定内容
Color color = Color.BLUE;
System.out.println(color);
//遍历枚举常量
//枚举.values()方法将全部的枚举常量变成数组,之后使用foreach输出
Color[] colors = Color.values();
for (Color c : colors)
{
//ordinal()方法返回枚举常量序号
//name()方法返回枚举常量名称
System.out.println(c.ordinal() + " ---> " + c.name());
}
//枚举和switch
switch(Color.BLUE){
case RED :
System.out.println("red");
break;
case BLUE :
System.out.println("blue");
break;
case BLACK :
System.out.println("black");
break;
default :
System.out.println("doesn't exist!");
}
}
}
四、枚举类实现一个接口
每一个枚举类对象都实现接口的抽象方法, 其实枚举类实现接口和普通类没多少区别,也是使用implements关键字,可以实现一个或多个接口。但是需要注意的是,如果像普通类一样实现接口后直接重写接口里的方法的话,那么枚举类的所有实例就拥有一样的接口实现了,这样就失去了意义和灵活性,所以往往会为每个实例提供不同的方法实现。示例代码如下:
package com.wbf.enum3;
interface Print {
//public abstract String getColor();
String getColor();
}
//枚举类实现一个接口
//每一个枚举类对象都实现接口的抽象方法
enum Color implements Print {
RED {
public String getColor(){
return "红色";
}
},
BLUE {
public String getColor() {
return "蓝色";
}
},
BLACK {
public String getColor() {
return "黑色";
}
};
}
public class EnumDemo3 {
public static void main(String[] args) {
Color c = Color.BLACK;
System.out.println(c.getColor());
}
}
五、枚举类中定义抽象方法
每一个枚举对象都会实现该抽象方法,类似与实现接口中的抽象方法。
枚举类中定义了抽象方法,但是,类却没用abstract修饰,这点跟普通类不一样,因为枚举类需要显示创建枚举值,并为抽象方法提供实现,否则会出现编译错误。
示例代码如下:
package com.wbf.enum4;
//枚举类中定义抽象方法
//每一个枚举对象都会实现该抽象方法
enum Color {
RED {
public String getColor(){
return "红色";
}
},
BLUE {
public String getColor() {
return "蓝色";
}
},
BLACK {
public String getColor() {
return "黑色";
}
};
public abstract String getColor();
}
public class EnumDemo4 {
public static void main(String[] args) {
Color c = Color.BLACK;
System.out.println(c.getColor());
}
}
六、通过构造方法,为每一个枚举对象属性赋值
因为在枚举类中已经明确的写出了一个带有参数的构造方法,所以定义枚举常量的时候就必须调用该构造方法。代码实例如下:
package com.wbf.enum5;
enum Color {
//因为在枚举类中已经明确的写出了一个带有参数的构造方法,所以定义枚举常量的时候就必须调用该构造方法
RED("红色"), BLUE("蓝色"), BLACK("黑色");
private String name;
private Color(String name){
System.out.println("构造方法被调用...");
this.setName(name);
}
public void setName(String name){
this.name = name;
}
public String getName(){
return this.name;
}
}
//通过构造方法,为每一个枚举对象属性赋值
public class EnumDemo5 {
public static void main(String[] args) {
for (Color c : Color.values())
{
System.out.println(c.ordinal() + " ---> " + c.name() + "(" + c.getName() + ")");
}
}
}
七、通过setter方法为每一个枚举对象的属性赋值
这样的话就必须明确的知道是哪一个枚举常量,枚举常量是RED, 则name属性应该是"红色"。代码实例如下:
package com.wbf.enum7;
enum Color {
RED, BLUE, BLACK;
private Color(){
System.out.println("构造方法被调用...");
}
private String name;
public void setName(String name){
switch(this){
case RED :{
if ("红色".equals(name)){
this.name = name;
} else {
System.out.println("设置内容错误");
}
break;
}
case BLUE : {
if ("蓝色".equals(name)){
this.name = name;
} else {
System.out.println("设置内容错误");
}
break;
}
case BLACK : {
if ("黑色".equals(name)){
this.name = name;
} else {
System.out.println("设置内容错误");
}
break;
}
}
}
public String getName(){
return this.name;
}
}
//通过setter方法为每一个枚举对象的属性赋值,但是这样的话就必须明确的知道是哪一个枚举常量
//如:枚举常量是RED, 则name属性应该是"红色"
public class EnumDemo7 {
public static void main(String[] args) {
Color c = Color.BLACK;
c.setName("蓝色");
c.setName("黑色");
System.out.println(c.getName());
}
}
八、类集对枚举的支持EnumMap, EnumSet
示例代码:
package com.wbf.enum6;
import java.util.EnumMap;
import java.util.EnumSet;
import java.util.Map;
enum Color {
RED, BLUE, BLACK;
}
//类集对枚举的支持EnumMap, EnumSet
public class EnumDemo6 {
public static void main(String[] args) {
//EnumMap, Map接口的子类, 要使用EnumMap必须先创建EnumMap对象, 创建此对象时必须指定要操作的枚举类型
Map<Color, String> enumMap = new EnumMap<Color, String>(Color.class);
enumMap.put(Color.RED, "红色");
enumMap.put(Color.BLUE, "蓝色");
enumMap.put(Color.BLACK, "黑色");
System.out.println("---输出全部内容---");
for (Color c : Color.values())
{
System.out.println(c.name() + ", " + enumMap.get(c));
}
System.out.println("---输出keys---");
for (Color c : enumMap.keySet())
{
System.out.println(c.ordinal() + " ---> " + c.name());
}
System.out.println("---输出values---");
for (String s : enumMap.values())
{
System.out.println(s);
}
//EnumSet是Set接口的子类,内容不可重复,不能够直接使用关键字new对其进行实例化,但是所在的类提供了很多static方法
System.out.println("---将全部的枚举值设置到EnumSet中---");
EnumSet<Color> enumSet1 = EnumSet.allOf(Color.class);
print(enumSet1);
System.out.println("---只设置一个枚举常量到EnumSet中---");
EnumSet<Color> enumSet2 = EnumSet.of(Color.BLUE);
print(enumSet2);
System.out.println("---创建只能够放入指定枚举类型的EnumSet---");
EnumSet<Color> enumSet3 = EnumSet.noneOf(Color.class);
enumSet3.add(Color.RED);
enumSet3.add(Color.BLUE);
print(enumSet3);
System.out.println("---创建不包含指定元素的集合---");
EnumSet<Color> enumSet4 = EnumSet.complementOf(enumSet3);
print(enumSet4);
System.out.println("---复制已有的内容---");
EnumSet<Color> enumSet5 = EnumSet.copyOf(enumSet3);
print(enumSet5);
}
public static void print(EnumSet<Color> temp){
for (Color c : temp)
{
System.out.print(c.name() + "、");
}
System.out.println();
}
}
九、小结
1)使用enum定义的枚举类默认继承了java.lang.Enum类,而不是直接继承Object类。java.lang.Enum类实现了java.lang.Serialiable和java.lang.Comparable两个接口,证明枚举类型可以使用比较器和序列化操作。
2)枚举类的构造器只能使用private修饰,即使省略也默认是private的。
3)枚举类实例只能显示给出,否则永远不能产生实例,列出这些实例时,系统会自动添加public static final修饰,无需程序员显示添加。
4)所有枚举类都提供了一个values方法,用于可以很方便地遍历所有枚举值。