枚举(Enum)
- 一、版本历史
- 二、什么是枚举
- 1.创建一个枚举类
- 2.实现接口
- 3.枚举中的方法
- 4.专用集合EnumSet和EnumMap
- 三、枚举和常量的比较
本文主要讲解Java枚举的使用以及与使用常量的区别,由于本人水平有限,写作之前参考了几位大神的文章,对枚举的应用有了更深的理解。特记录下本文章,以供自己翻阅。
一、版本历史
枚举(Enum)是JDK1.5版本新增的特性,1.5版本新增的特性还有泛型,For-each。JDK 1.6版本之后,switch case语句支持枚举类型的判断。
二、什么是枚举
枚举(Enum)是一种特殊的数据类型,它即是一种类(class)类型又比这个类型多了些特殊的约束。这些约束使其类更加的安全,方便使用。
1.创建一个枚举类
enum UserType{
USER("USER","内部用户",1),CUSTOMER("CUSTOMER","消费者",2),PARTNER("PARTNER","合作商",3);
private String userType;
private String typeName;
private Integer typeIndex;
private UserType(String userType,String typeName,Integer typeIndex){
this.userType=userType;
this.typeName=typeName;
this.typeIndex=typeIndex;
}
// get set 方法
@Override
public String toString() {
return this.userType+"_"+this.typeName;
};
System.out.println(UserType.USER.getTypeName()); // 内部用户
System.out.println(UserType.USER); // USER 没有复写toString()方法
System.out.println(UserType.USER); // USER_内部用户 复写了toString()方法
枚举是一个特殊的类,它也有实例字段、构造器和方法。默认无参构造器不能够被声明并且所有的构造器必须被private修饰,枚举实例用","
隔开,序列的最后用";"
结束
创建一个枚举类要使用关键字 enum
,隐藏的含义为该枚举类自动继承了java.lang.Enum<T>
(抽象泛型类),只能实现接口而不能继承,Java编译器在编译时做了这个转换
enum UserType extends Eunum<UserType>{
// something
};
实际上每一个继承自Enum<T>
的枚举允许定义泛型类、接口和方法,通过这种方式可以让枚举类型的实例参数化或者类型参数化。比如:
public<T extends Enum< ? >> void performAction(final T instance) {
// Perform some action here
}
在上面的声明中,类型T被约定为任意枚举类型的实例并且Java编译器将会对其做验证
2.实现接口
interface IsUser{
boolean ifUser();
}
两种实现方式:
①
enum UserType implements IsUser{
USER("USER",true),CUSTOMER("CUSTOMER",true)
private String userType;
private boolean isUser;
UserType(String userType,boolean isUser){
this.userType=userType;
this.isUser=isUser;
}
boolean ifUser(){
return this.isUser;
}
}
System.out.println(UserType.USER.isUser()); //true
②
enum UserType implements IsUser{
USER("USER"){
@Override
public boolean isUser() {
return true;
}
},CUSTOMER("CUSTOMER"){
@Override
public boolean isUser() {
return false;
}
};
private String userType;
private boolean isUser;
UserType(String userType,boolean isUser){
this.userType=userType;
this.isUser=isUser;
}
}
System.out.println(UserType.USER.isUser()); //true
③使用接口组织枚举
public interface IsUser{
enum UserType implements IsUser{
USER,CUSTOMER;
}
}
System.out.println(IsUser.UserType.USER); // USER
3.枚举中的方法
基础类 Enum<T>
为自动继承它的枚举实例提供了一些非常有用的方法。
方法 | 描述 |
String name() | 返回枚举声明声明的枚举常量的名称 |
int ordinal() | 返回枚举常量的次序(即枚举声明时的位置,初始常量分配的位置是0) |
Java编译器为每个枚举类型自动生成两个更有用的静态方法(让我们将这个特殊的枚举类型假设为T)。
方法 | 描述 |
T[] values() | 返回枚举T所声明的所有常量 |
T valueOf(String name) | 返回指定名称的枚举常量 |
System.out.println(UserType.valueOf("USER")); // 调用toString方法
System.out.println(UserType.USER.ordinal()); // 0
上面代码中valueOf()的参数值为 实例名的字符串形式
,不是该实例的变量值
4.专用集合EnumSet和EnumMap
和所有其他类一样,枚举的实例也可以和标准Java集合库一起使用。然而,某些集合类型针对枚举做了优化,并且在大多数情况下推荐使用这些优化过后的集合代替通用的集合。
我们首先来看一下EnumSet集合。EnumSet集合是常规的集合优化过后高效存储枚举类型的一个集合,EnumSet不能够使用构造器进行实例化,但是它提供了很多非常有用的工厂方法。
// allOf工厂方法创建的EnumSet<T>实例就包含了所有枚举类型所枚举的常量:
final Set<DaysOfTheWeek> enumSetAll = EnumSet.allOf(DaysOfTheWeek.class);
//noneOf工厂方法创建的是一个空的EnumSet<T>实例
final Set<DaysOfTheWeek> enumSetNone = EnumSet.noneOf(DaysOfTheWeek.class);
//使用of工厂方法,可以指定枚举类型中那些枚举常量应该包含在EnumSet<T>中:
final Set< DaysOfTheWeek > enumSetSome = EnumSet.of(
DaysOfTheWeek.SUNDAY,
DaysOfTheWeek.SATURDAY
);
EnumMap<T, ?>是最接近于一般的map的,唯一的不同就是EnumMap<T, ?>的key是枚举类型的枚举常量
final Map<DaysOfTheWeek, String> enumMap = new EnumMap<>(UserType.class);
enumMap.put(UserType.USER, "Lundi");
三、枚举和常量的比较
使用常量时
- 常量作为参数时,是String,int等弱类型,开发人员可以传入没有在常量接口里定义的值,这个问题无法通过编译器发现。
- 由于开发人员可以直接写常量,所以不能用==对比,只能用equals对比,不能优化性能。
- 开发人员没有参考资料时,不可能知道某个int类型的参数到底应该赋什么内容。
- 编译时,是直接把常量的值编译到类的二进制代码里,常量的值在升级中变化后,需要重新编译引用常量的类,因为里面存的是旧值。
- 如果常量类的构造器不私有,无法限制开发员继承/实现接口,开发员能够在子接口里继续添加常量.而这些常量可能得不到祖先层的支持。
使用枚举时
- 私有构造函数,避免被继承和扩展。
- 定义方法的参数时,必须用枚举常量类类型,如上面的Constant,这样就转变成了强类型,不会出现弱类型引用的问题。
- 常量值地址唯一,可以用==直接对比,性能会有提高。
- 编译时,没有把常量值编译到代码里,即使常量的值发生变化,也不会影响引用常量的类。