引例
当一个变量只能在一个有限集合内取值时,可以考虑使用枚举类型。比如,衣服尺寸分别编码为S、M、L、X,如果int数字1~4表示这4个编码,可能会出现一些问题:例如,衣服尺寸变量可能为0或者>4的数字,但是程序可能还不清楚含义。
对于这种情况,可以定义枚举类型,表示衣服尺寸所有可能编码enum Size{SMALL, MEDIUM, LARGE, EXTRA_LARGE}
声明变量表示一件衣服尺寸为MSize s = Size.MEDIUM
这样,衣服尺寸就只能是枚举类型的枚举值,没有任何值用null表示。
定义枚举类enum
定义一个枚举类型实际上也是定义一个类,所有枚举类型都继承自Enum类。
public enum Size{ SMALL, MEDIUM, LARGE, EXTRA_LARGE }
既然枚举类型Size也是类,那是为什么没有构造器、方法和域呢?
因为所有的枚举类都继承自Enum类,子类使用Java编译器提供的缺省构造器。作为枚举类型,主要目的是提供对枚举值的支持,如果单纯使用类的功能,更建议用普通class而非enum。
如果需要使用显示构造器,也是可以的,比如
// 使用构造器的枚举类
public enum Size {
SMALL("S"),
MEDIUM("M"),
LARGE("L"),
EXTRA_LARGE("XL");
private String abbreviation; // 名称自定义
Size(String abbreviation) {
this.abbreviation = abbreviation;
}
public String getAbbreviation() {
return abbreviation;
}
}
枚举类型的使用
获取枚举常量名
获取单个枚举常量名String t = Size.SMALL.toString(); // 获取枚举常量名 'SMALL'
获取所有枚举常量
Size[] values = Size.values(); // values是包含Size.SMALL, Size.MEDIUM, Size.LARGE, Size.EXTRA_LARGE的数组
// 打印每个枚举常量名
for(Size size: values) {
System.out.println(size);
}
枚举名 -> 枚举常量
从枚举常量名构建枚举变量Size s = Enum.valueOf(Size.class, "SMALL"); // valueOf是toString逆
比较枚举类型
比较两个枚举类型变量是否相等,使用 “==”,而不要使用“equals”。
Size s1 = Size.MEDIUM;
Size s2 = Size.LARGE;
if(s1 == s2)
System.out.println("s1 == s2");
else System.out.println("s1 ≠ s2");
获取枚举常量出现位置
可以利用Enum的orinal()方法获取枚举常量在定义中出现位置。枚举常量位置值从0开始,逐渐递增。
枚举常量值无法通过像C那样通过设置enum{SMALL=1, MEDIUM, LARGE, EXTRA_LARGE}
修改,通过API只能获取枚举常量在定义中出现位置顺序,而不能修改枚举值本身的值。
// 枚举类型Size定义
public enum Size{ SMALL, MEDIUM, LARGE, EXTRA_LARGE }
Size s1 = Size.SMALL;
int a = s1.ordinal(); // a = 0, 对应枚举常量Size.SMALL在定义中的出现顺序
枚举类与单例模式
单例模式需要实现的目标是:创建只有一个实例引用(或指针)共享使用,单例模式3个特点:
- 单例类构造方法私有;
- 单例类实例变量引用唯一并且私有化;
- 单例类提供给其他对象这一私有化实例引用(如getInstance);
单例模式还需要关注的点:
- 是否延迟实例化;
- 是否多线程安全;
方式一:利用枚举类型直接构造单例类
这种方式利用了枚举类型只会装载一次的特性,等同于饿汉式,虽然线程安全,不过没有延迟实例化。
/**
* 延迟实例化:否
* 多线程安全:是
*/
public enum User{
INSTANCE;
private User() {
}
public static User getInstance() {
return User.INSTANCE;
}
}
// 等价于饿汉式
public class User{
private static User instance = new User();
private User() {}
public static User getInstance() {
return instance;
}
}
方式二:枚举类作为单例类的内部类
利用枚举类只会