枚举
枚举类型是java 5中新增特性的⼀部分,它被用来将⼀组类似的值包含到⼀种类型当中,
面这种枚举类型的名称则会被定义成独⼀⽆⼆的类型描述符,在这⼀点上和常量的定义相似。
不过相比较常量类型,枚举类型可以为申明的变量提供更⼤的取值范围。
以前定义⼀个常量是在类或接口中声明,比如下面的代码:
public class Color{
public static final int RED = 0;
public static final int GREEN = 1;
public static final int BLACK = 1;
}
但这种方式主要的问题有如下⼏点:
- 类型不安全: 因为这些常量本质上还是整数,你仍然可以传入任意整数类型的值,这样是可能导致错误的.
- 一致性差: 因为整形枚举属于编译期常量,
所以编译过程完成后,所有客户端和服务器端引用的地方,
会直接将整数值写入。这样,当你修改旧的枚举整数值后或者增加新的枚举值后,
所有引用地方代码都需要重新编译,否则运行时刻就会出现错误。
- 类型无指意性:由于颜色枚举值仅仅是⼀些无任何含义的整数值,如果在运行期调试时候,
你就会发现日志中有很多魔术数字,但除了程序员本身,其他人很难明白其奥秘。
基本使用
枚举不仅是简单地将整形数值转换成对象,而是将枚举类型定义转变成⼀个完整功能的类定义。
这种类型定义的扩展允许开发者给枚举类型增加任何方法和属性,也可以实现任意的接口。
另外,自定义的枚举类型默认继承了Enum这个抽象类,此抽象类默认实现 Comparable 和 Serializable 接口。
由于定义的枚举继承了Enum类,会从此类继承⼀些有用的方法,常⻅的方法如下:
- ordinal:实例方法,返回枚举项的序号,也就是在枚举声明中的序号,第⼀项的值为0,依次递增.
- name:实例方法,返回枚举常量的名称
- valueOf:静态方法,依据枚举常量得到对应的枚举对象
- values:静态方法,返回每⼀个枚举常量代表的枚举对象
public enum Color {
/**
* 颜色
*/
RED("红色"),GREEN("绿色"),BLACK("黑色");
/**
* 颜色名称
*/
private final String colorName;
Color(String colorName) {
this.colorName = colorName;
}
public String getColorName() {
return colorName;
}
}
添加抽象方法或者实现接口
枚举类中可以添加抽象方法,由于每⼀个枚举类型都是final的,所以此抽象方法的实现地方就是枚举类本身,并且每⼀个枚举常量都需要实现此方法。
由于枚举继承于Enum,它是个类,所以其也也可实现接口,让枚举实现接口的⼀种典型用法是利用接口组织各种枚举类型。
例如:
public enum Color {
/**
* 颜色
*/
RED("红色"){
@Override
public String getColorRemark(String user) {
return user + "喜欢红色";
}
},GREEN("绿色"){
@Override
public String getColorRemark(String user) {
return user + "喜欢绿色";
}
},BLACK("黑色"){
@Override
public String getColorRemark(String user) {
return user + "喜欢黑色";
}
};
/**
* 颜色名称
*/
private final String colorName;
Color(String colorName) {
this.colorName = colorName;
}
public String getColorName() {
return colorName;
}
/**
* 获取颜色备注的方法
* @return 颜色备注
*/
public abstract String getColorRemark(String user);
/**
* 方便通过值获取对象
* @param type 值
* @return 对象
*/
public static Color getEnum(String type){
Color result = null;
Color[] colors = Color.values();
for (Color color : colors) {
if (color.getColorName().equals(type)) {
result = color;
}
}
MyAssert.isNotNull(result, "Get type: "+type+" Color fails");
return result;
}
}
这是一个添加抽象方法的枚举,使用这样的枚举能有效地避免多次if...else或者switch的使用和定义。
接口和抽象方法操作相似。
public class Main {
private static final String RED_ZH_NAME = "红色";
private static final String GREEN_ZH_NAME = "绿色";
public static void main(String[] args) {
String colorName = "黑色";
String user = "超人不会飞";
String value = Color.getEnum(colorName).getColorRemark(user);
/*
value ==> 超人不会飞喜欢黑色
相当于
if(RED_ZH_NAME.equals(colorName)) {
value = user + "喜欢红色";
}else if (GREEN_ZH_NAME.equals(colorName)){
value = user + "喜欢绿色";
}else {
value = user + "喜欢黑色";
}
*/
}
}
EnumSet
JDK5.0 中在增加 Enum 类的同时,也增加了两个工具类 EnumSet 和 EnumMap,这两个类都放在 java.util 包中。
EnumSet 是⼀个针对枚举类型的高性能的 Set 接口实现。此类是⼀个抽象类,主要是使⽤其静态方法来操作各种枚举类型,
主要的静态方法如下:
- range: 创建⼀个包含枚举值中指定范围的枚举对象集合
- allOf:创建⼀个枚举所有常量值代表的对象集合
- noneOf: 创建⼀个指定枚举类型的空集合
- of: 创建⼀个包含方法参数指定的所有元素的集合
- copyOf: 创建⼀个参数集合中的所有元素的集合
EnumMap
EnumMap 也是⼀个高性能的 Map 接口实现,用来管理使用枚举类型作为 keys 的映射表,并且键不能允许为null。
EnumMap与普通的Map集合使用起来基本差不多,但它是⼀个专⻔高效处理枚举作为键的高效Map集合实现。
Class对象中的枚举
class对象中关于枚举的相关功能主要是getEnumConstants方法与isEnum方法.
- getEnumConstants方法返回枚举类型的所有元素,如果class对象不是枚举类型返回null,此方法作用类似枚举类型的values方法。
- isEnum方法用来判断是否是⼀个枚举类型。
使用注意
- enum 类型不支持 public 和 protected 修饰符的构造方法,因此构造函数⼀定要是 private 或 friendly的。
也正因为如此,所以枚举对象是无法在程序中通过直接调用其构造方法来初始化的。 - 定义 enum 类型时候,如果是简单类型,那么最后⼀个枚举值后不用跟任何⼀个符号;
但如果有定制方法,那么最后⼀个枚举值与后面代码要用分号 ; 隔开,不能用逗号或空格。 - 由于 enum 类型的值实际上是通过运行期构造出对象来表示的,所以在 cluster 环境下,每个虚拟机都会构造出⼀个同义的枚举对象。
因而在做比较操作时候就需要注意,如果直接通过使用等号 ( ‘ == ’ ) 操作符,这些看似⼀样的枚举值⼀定不相等,因为这不是同⼀个对象实例。 - 枚举类是不能被继承的,因为每⼀个枚举类都是final的