一:枚举类
枚举是JDK1.5添加的,在枚举类型出来之前,我们都是以定义常量来代替,比如:

这种定义常量的方式也是有一些不足的,如int值相同的情况下,编译期并不会提示我们的,所以很容易造成混淆。
定义枚举类的一般语法:任意两个枚举成员不能具有相同的名称,多个枚举成员之间使用逗号分隔,枚举表示的类型其取值是必须有限的
二:枚举类原理
把刚才定义的Date枚举类编译后再反编译class文件来看一下:
可以看到,使用关键字enum定义的枚举类型,在编译期后,也将转换成为一个实实在在的类,而在该类中,会存在每个在枚举类型中定义好变量的对应实例对象,如上述的ONE枚举类型对应public static final Date ONE;,同时编译器会为该类创建两个方法,分别是values()和valueOf()。
- 枚举类实际上也是一个类,默认继承于java.lang.Enum类,并且此类是final的,不可被继承,又由于java是单继承已经默认继承Enum所以我们定义的Date枚举类是不允许继承其他类的。
- 默认生成私有构造函数,只能由虚拟机去创建,不允许外部直接创建枚举类对象的。
- 定义的枚举实际上是枚举类型的常量。
java.lang.Enum源码
下面例子测试其方法:
运行输出:
Values()方法与ValueOf()方法
values()方法和valueOf(String name)方法是编译器生成的static方法,在Enum类中并没出现values()方法,但valueOf()方法还是有出现的,只不过编译器生成的valueOf()方法需传递一个name参数,而Enum自带的静态方法valueOf()则需要传递两个方法,其实,编译器生成的valueOf方法最终还是调用了Enum类的valueOf方法:
运行输出:
values()方法的作用就是获取枚举类中的所有变量,并作为数组返回。
valueOf(String name)方法与Enum类中的valueOf方法的作用类似根据名称获取枚举变量。
三:枚举类使用
- enum 与 class、interface 具有相同地位,但是不能继承与被继承,也不能创建实例,只能由JVM去创建。
- 可以实现多个接口,也可以拥有构造器、成员方法、成员变量。
实现接口
定义构造函数
注意:只能是私有的构造函数或默认
定义成员方法和成员变量
EnumMap
java.util.EnumSet和java.util.EnumMap是两个枚举集合。EnumMap继承了AbstractMap类,因此EnumMap具备一般map的使用方法,主要通过一个保存key的数组K[] keyUniverse和一个保存value的数组Object[] vals来操作。
源码:
下面例子测试其方法:
运行输出:
{ONE=1, THREE=3}
EnumSet
EnumSet是与枚举类型一起使用的专用 Set 集合,EnumSet 中所有元素都必须是枚举类型。注意EnumSet不允许使用 null 元素。试图插入 null 元素将抛出 NullPointerException,但试图测试判断是否存在null 元素或移除 null 元素则不会抛出异常,与大多数collection 实现一样,EnumSet不是线程安全的,因此在多线程环境下应该注意数据同步问题。
public abstract class EnumSet> extends AbstractSet
implements Cloneable, java.io.Serializable
//元素的class
final Class elementType;
final Enum>[] universe;
private static Enum>[] ZERO_LENGTH_ENUM_ARRAY = new Enum>[0];
this.elementType = elementType;
this.universe = universe;
}
//创建一个具有指定元素类型的空EnumSet。
Enum>[] universe = getUniverse(elementType);
if (universe == null)
throw new ClassCastException(elementType + " not an enum");
if (universe.length <= 64)
return new RegularEnumSet<>(elementType, universe);
else
return new JumboEnumSet<>(elementType, universe);
}
//创建一个指定元素类型并包含所有枚举值的EnumSet
EnumSet result = noneOf(elementType);
result.addAll();
return result;
}
abstract void addAll();
创建一个包含参数容器中的所有元素的EnumSet
return s.clone();
}
return ((EnumSet)c).clone();
if (c.isEmpty())
throw new IllegalArgumentException("Collection is empty");
Iterator i = c.iterator();
E first = i.next();
EnumSet result = EnumSet.of(first);
while (i.hasNext())
result.add(i.next());
return result;
}
}
// 初始集合包括指定集合的补集
EnumSet result = copyOf(s);
result.complement();
return result;
}
// 创建一个包括参数中所有元素的EnumSet
EnumSet result = noneOf(e.getDeclaringClass());
result.add(e);
return result;
}
EnumSet result = noneOf(e1.getDeclaringClass());
result.add(e1);
result.add(e2);
return result;
}
EnumSet result = noneOf(e1.getDeclaringClass());
result.add(e1);
result.add(e2);
result.add(e3);
return result;
}
EnumSet result = noneOf(e1.getDeclaringClass());
result.add(e1);
result.add(e2);
result.add(e3);
result.add(e4);
return result;
}
public static > EnumSet of(E e1, E e2, E e3, E e4,
E e5)
EnumSet result = noneOf(e1.getDeclaringClass());
result.add(e1);
result.add(e2);
result.add(e3);
result.add(e4);
result.add(e5);
return result;
}
@SafeVarargs
EnumSet result = noneOf(first.getDeclaringClass());
result.add(first);
for (E e : rest)
result.add(e);
return result;
}
// 创建一个包括枚举值中指定范围元素的EnumSet
if (from.compareTo(to) > 0)
throw new IllegalArgumentException(from + " > " + to);
EnumSet result = noneOf(from.getDeclaringClass());
result.addRange(from, to);
return result;
}
abstract void addRange(E from, E to);
@SuppressWarnings("unchecked")
return (EnumSet) super.clone();
throw new AssertionError(e);
}
}
abstract void complement();
Class> eClass = e.getClass();
if (eClass != elementType && eClass.getSuperclass() != elementType)
throw new ClassCastException(eClass + " != " + elementType);
}
return SharedSecrets.getJavaLangAccess()
.getEnumConstantsShared(elementType);
}
}
下面例子测试其方法:
创建EnumSet并不能使用new关键字,因为它是个抽象类,而应该使用其提供的静态工厂方法,EnumSet的静态工厂方法比较多,如下:
运行输出: