枚举使用关键字 enum 进行定义,每个元素都是一个实例,如下,FOO 和 BAR 都是一个 EnumClazz 实例。
public enum EnumClazz {
FOO,
BAR;
}
枚举类默认继承 Enum 类。
方法添加
我们可以给枚举实例添加一些对自身的描述,这是通过构造函数实现的
public enum EnumClazz {
FOO("this is foo"),
BAR("this is bar");
EnumClazz(String desc) {
}
}
但是这样是拿不到 desc 信息的,需要为其添加一个获取 desc 的方法。
public enum EnumClazz {
FOO("this is foo"),
BAR("this is bar");
private String desc;
private String getDesc(){
return desc;
}
EnumClazz(String desc) {
this.desc = desc;
}
}
values 方法
我们定义的枚举类都是继承自 Enum 类,但是 Enum 类并没有 values() 方法,那么 values() 方法是怎么来的呢,答案是编译器自动帮我们生成的。values() 方法可以获取到枚举类的所有实例,下面是常规使用方法:
value() 方法是接收一个 code 值,获取对应的枚举实例。
public enum EnumClazz {
FOO(1),
BAR(2);
private Integer code;
private Integer getCode() {
return code;
}
EnumClazz(Integer code) {
this.code = code;
}
public EnumClazz value(Integer code) {
if (code == null) return null;
for (EnumClazz value : EnumClazz.values()) {
if (Objects.equals(value.getCode(), code)) {
return value;
}
}
return null;
}
}
EnumSet
枚举类的每个实例其实都维护着一个顺序值,按照定义顺序来递增
EnumSet 采用 bit 位来实现,内部是使用 Long 类型来维护的,哪个枚举被塞入 EnumSet ,那么对应的 bit 位就制为1,由于是采用 bit 位进行操作的,因此速度非常快。Long 只有 64 位,但是 EnumSet 却可以存储超过 64 个枚举实例,估摸着是采用了多个 Long。
public enum EnumClazz {
FOO,
BAR;
public static void main(String[] args) {
System.out.println(EnumClazz.FOO.ordinal());
System.out.println(EnumClazz.BAR.ordinal());
EnumSet<EnumClazz> set = EnumSet.allOf(EnumClazz.class);
System.out.println(set.contains(EnumClazz.FOO));
}
}
输出:
0
1
true
EnumMap
EnumMap 的 key 只能是枚举,由于枚举的特殊性,每个实例都有自己的一个顺序值,可以用来定位,因此,直接采用数值来实现即可,我们知道,在知道数组下标的情况下,数组的顺序是非常快的。
public enum EnumClazz {
FOO,
BAR;
public static void main(String[] args) {
EnumMap<EnumClazz, String> map = new EnumMap<EnumClazz, String>(EnumClazz.class);
map.put(EnumClazz.FOO, "foo");
map.put(EnumClazz.BAR, "bar");
System.out.println(map);
}
}
输出:
常量特定方法{FOO=foo, BAR=bar}
由于每个属性都是一个枚举实例,那么,我们是不是可以在枚举类中定义方法,然后在实例中实现他们,从而采取不同的行为呢,就像多态那样。这是可以做到的(描述的有点乱,直接看代码,代码一看就懂)。
如下,在枚举类 EnumClazz 中定义一个抽象方法,在每个实例,在这里是 FOO 实例和 BAR 实例中实现改方法即可。当然,不是抽象方法也行。
public enum EnumClazz {
FOO {
void showInfo() {
System.out.println("I am foo");
}
},
BAR {
void showInfo() {
System.out.println("I am bar");
}
};
abstract void showInfo();
public static void main(String[] args) {
EnumClazz.BAR.showInfo();
EnumClazz.FOO.showInfo();
}
}
输出:
有意思的枚举使用方式I am bar
I am foo
在 Java 编程思想中,看到一个有意思的枚举使用方式,特此记录下来。
有时候,我们多个枚举类,但是这些枚举类又属于同一个大类目。举个栗子,水果下面分为香蕉、苹果、西瓜,香蕉分为米蕉、芝麻蕉、李林蕉,苹果分为:红玉苹果、金冠苹果、国光苹果,西瓜分为麒麟西瓜、黑美人西瓜、特小凤西瓜。其中可以创建水果枚举,香蕉枚举,苹果枚举,西瓜枚举,其中香蕉、苹果、西瓜枚举分别管理各自的品种,而水果枚举则管理着香蕉、苹果、西瓜枚举。也就是枚举的枚举。
这样的管理方式可以使用接口组织枚举
接口组织枚举
如下栗子,感觉还挺有意思的。
public enum FruitEnum {
BANANA(FruitInterface.Banana.class),
APPLE(FruitInterface.Apple.class),
WATERMELON(FruitInterface.Watermelon.class);
FruitInterface[] fruits;
FruitEnum(Class<? extends FruitInterface> clazz) {
fruits = clazz.getEnumConstants();
}
interface FruitInterface {
enum Banana implements FruitInterface {
MI,
LILIN,
SESAME;
}
enum Apple implements FruitInterface {
CARBUNCLE,
GOLDEN_ROWN,
GUO_GUANG;
}
enum Watermelon implements FruitInterface {
QILIN,
BLACK_BEAUTY,
TE_XIAO_FENG
}
}
public static void main(String[] args) {
Random ran = new Random();
FruitEnum[] fruits = FruitEnum.class.getEnumConstants();
FruitEnum fruit = fruits[ran.nextInt(3)];
FruitInterface[] randomFruits = fruit.fruits;
for (FruitInterface item : randomFruits) {
System.out.println(item);
}
}
}
输出
QILIN
BLACK_BEAUTY
TE_XIAO_FENG