简介
Java的枚举类型用于在某些东西可以枚举出来的时候,我们可以把它定义为枚举类型,然后把其中包含的可选值一一枚举。打个比方,我们现在有一堆数字,大致可以分为四种类型,整型、浮点型、金额和百分比。整型的我就需要按整型显示,如果是浮点型则要求保留两位小数,如果是金额则要求按千分位展示,如果是百分比则要求显示对应的百分比。为此我们就定义了一个枚举类型NumberType,其一共四个枚举值,每个枚举值之间用逗号分隔,最后一个枚举值用分号结束(也可以不用,但是如果最后一个值后面还有其它内容时必须用分号结束)。
public enum NumberType {
/**
* 整型
*/
INTEGER,
/**
* 浮点型
*/
FLOAT,
/**
* 金额
*/
CURRENCY,
/**
* 百分比
*/
PERCENT;
}
对于这样的需求可能你觉得没必要使用枚举类型,我使用一个常量类,里面定义4个常量也是可以的,如下这样。
public class NumberTypes {
/**
* 整型
*/
public static final int INTEGER = 1;
/**
* 浮点型
*/
public static final int FLOAT = 2;
/**
* 金额
*/
public static final int CURRENCY = 3;
/**
* 百分比
*/
public static final int PERCENT = 4;
}
对的,定义一个常量类也可以达到对应的效果,但是在使用枚举类的时候将更加的方便。例如我们的类型是安全的,当你使用枚举类型时你传递的只能是对应的枚举类型里面包含的枚举元素,而你使用常量时你传递的类型只能是一个Integer,但是调用者完全有可能传入一个你没有定义的Integer。下面还会介绍一些枚举的功能,通过下面的介绍你就会觉得很多时候用枚举比用一个常量类功能更加的强大。
成员变量/构造方法
枚举类型跟interface一样,也是Java类的一种,只是比较特殊的一种Java类。其也可以定义自己的成员变量、构造方法等。非枚举值必须定义在枚举值之后。如下,我们定义了一个成员变量code,和一个基于成员变量code的构造方法,我们的构造方法必须是private的,因为它是不能通过外部调用的。
public enum NumberType {
/**
* 整型
*/
INTEGER(1),
/**
* 浮点型
*/
FLOAT(2),
/**
* 金额
*/
CURRENCY(3),
/**
* 百分比
*/
PERCENT(4);
/**
* 成员变量,内部编码
*/
private int code;
/**
* 构造方法
* @param code
*/
private NumberType(int code) {
this.code = code;
}
}
对于枚举类型而言,其中定义的每一个枚举值就相当于对应枚举类型的一个具体对象,其在构造的时候必须利用对应枚举类型的一个构造方法来初始化。在上面的示例中我们只定义了一个构造方法,所以我们的每一个枚举值在构造的时候都只能通过传递code的方式来初始化。枚举类型的构造方法也是可以有多个的,如上面的示例中我们还可以给它加一个无参构造方法和其它构造方法。
成员方法
枚举类型也可以定义自己的成员方法,其可以是public的,也可以是private的等。如下,我们定义了一个公用的getCode()方法,其在方法体里面返回了成员变量code。
public enum NumberType {
/**
* 整型
*/
INTEGER(1),
/**
* 浮点型
*/
FLOAT(2),
/**
* 金额
*/
CURRENCY(3),
/**
* 百分比
*/
PERCENT;
/**
* 成员变量,内部编码
*/
private intcode;
/**
* 无参构造,没意义
*/
private NumberType() {}
/**
* 构造方法
* @param code
*/
private NumberType(int code) {
this.code = code;
}
/**
* 获取对应的编码
* @return
*/
public int getCode() {
return this.code;
}
}
除了这种非抽象方法之外,枚举也可以定义抽象方法,抽象方法则要求每一个枚举值都必须实现。如下,当我们有一个需求就是根据不同类型的枚举值把对应的数据展示为不同的形式时我们就可以定义一个对应的show抽象方法,然后由各个枚举值根据自身的需求实现。
public enum NumberType {
/**
* 整型
*/
INTEGER(1) {
@Override
public String show(Object value) {
//只返回整型部分,去掉小数之类的
return null;
}
},
/**
* 浮点型
*/
FLOAT(2) {
@Override
public String show(Object value) {
//必须保留两位小数
return null;
}
},
/**
* 金额
*/
CURRENCY(3) {
@Override
public String show(Object value) {
//必须展示千分位
return null;
}
},
/**
* 百分比
*/
PERCENT {
@Override
public String show(Object value) {
//必须展示成百分比的形式,0.15变成15%
return null;
}
};
/**
* 成员变量,内部编码
*/
private int code;
/**
* 无参构造,没意义
*/
private NumberType() {}
/**
* 构造方法
* @param code
*/
private NumberType(int code) {
this.code = code;
}
/**
* 获取对应的编码
* @return
*/
public int getCode() {
return this.code;
}
/**
* 按照特定的形式展示数据
* @param value
* @return
*/
public abstract String show(Object value);
}
自带的成员方法
所有的枚举类型定义实际上都是隐式的继承了java.lang.Enum类作为自己的基类型的。Enum类型中主要定义了三个公用的成员方法。
name():返回对应的元素名称。
ordinal():返回对应的元素在枚举类型中定义的顺序号,第一个元素的顺序号是0。
compareTo():用来比较两个枚举类型对象,其返回结果是调用两个对象的ordinal()返回值进行相减。
静态方法
枚举类型也可以包含静态方法,如下示例中我们就定义了一个枚举类型NumberType的静态方法,get方法,通过NumberType的code来获取对应的NumberType。
public enum NumberType {
/**
* 整型
*/
INTEGER(1),
/**
* 浮点型
*/
FLOAT(2),
/**
* 金额
*/
CURRENCY(3),
/**
* 百分比
*/
PERCENT(4);
/**
* 成员变量,内部编码
*/
private int code;
/**
* 无参构造,没意义
*/
private NumberType() {}
/**
* 构造方法
* @param code
*/
private NumberType(int code) {
this.code = code;
}
/**
* 获取对应的编码
* @return
*/
public int getCode() {
return this.code;
}
/**
* 通过code来获取对应的NumberType
* @param code
* @return
*/
public static NumberType get(int code) {
NumberType[] values = NumberType.values();
for (NumberType value : values) {
if (value.getCode() == code) {
return value;
}
}
return null;
}
}
自带的静态方法
上一个示例中我们自己定义了枚举类型NumberType的静态方法,get方法。而实际上,在Java中所有的枚举类型都会自带三个静态方法。
values():获取当前枚举类型里面所有的元素,如上面示例中我们get静态方法的应用。
valueOf(String name):根据元素的名称来获取当前枚举类型里面的元素。
valueOf(Class<T> enumType, String name):根据元素名称来获取指定枚举类型里面的某个元素。
switch枚举类型
我们在使用枚举类型的时候如果要具体用到某个元素,我们都是通过“enum.ele”的形式来获取具体的某个元素应用的,如我们需要使用枚举类型NumberType的CURRENCY元素时,我们会使用NumberType.CURRENCY的形式来使用。但是在使用switch语句对枚举类型进行逻辑处理的时候,我们就不能再加上对应的枚举类型前缀了,而是需要直接使用对应的元素。如我们需要在switch语句中使用上述的NumberType时,我们应该以如下的方式来使用。
public void doSwitch(NumberType numberType) {
switch (numberType) {
case INTEGER:
System.out.println("整型");
break;
case FLOAT:
System.out.println("浮点型");
break;
case CURRENCY:
System.out.println("金额");
break;
case PERCENT:
System.out.println("百分比");
break;
}
}
EnumMap
有的时候我们可能需要把我们的枚举类型作为一个Map的Key来使用,这种情况的话官方建议我们直接使用EnumMap。EnumMap是Java专门为以枚举类型作为Key来构造的一个Map,其底层的元素是以数组的方式来存储的。这也比较好理解,因为枚举类型的元素一般不会很多,就算很多的话它的key也是固定的,所以EnumMap在初始化的时候就有一个数组与之对应了,数组的长度就是对应枚举类型的元素个数。EnumMap中对应的Key的值存储的就是存储在数组中索引为枚举类型元素的ordinal()的位置。
EnumSet
有的时候我们可能需要把我们的枚举类型对象存入到Set中,这种情况的话官方建议我们直接使用EnumSet。EnumSet在使用的时候不能直接new,它提供了一系列的静态of方法,用以基于某类型的枚举的某些元素来创建一个EnumSet,其返回结果都是一个EnumSet对象。
EnumSet<NumberType> enumSet = EnumSet.of(NumberType.CURRENCY, NumberType.PERCENT);