关键字enum可以将一组具名的值的有限集合创建为一种新的类型,这些具名的值可以作为常规的程序组件使用。
基本enum特性
调用enum的values()方法可以遍历enum实例。values()方法返回enum实例的数值,而且该数组中的元素严格保持其在enum中声明时的顺序,一次你可以在在循环中使用values()返回的数组。下面的例子演示Enum提供的一些功能:
ordinal()方法返回一个int值,这是每个enum实例在声明时的次序,从0开始。可以使用==比较enum实例,编译器自动提供equals()和hashCode方法。Enum类实现Comparable接口,它具有compareTo()方法,实现了Serializable接口。
如果在enum实力上调用getDeclaringClass()方法,能知道其所属的enum类。name()方法返回enum实例声明时的名字,这与使用toString()方法效果一样。,valueOf()是在Enum中定义的static方法,根据给定的名字返回相应的enum实例,如果不存在给定名字的实例将会抛出异常。
将静态导入用于enum:
使用static import能够将enum实例的标识符带入当前的命名空间,所以无需再用enum类型来修饰enum实例。
向enum中添加新方法
除了不能继承自一个enum之外,基本可以将enum看作为一个常规的类,可以在enum中添加方法。希望每个枚举实例能够返回对自身的描述,而不仅仅只是默认的toString()实现,只能返回枚举实例的名字。可以提供一个构造器,专门负责处理这个额外的信息,然后添加一个方法返回这个描述信息。
enum中的构造器与方法和普通的类没有区别。在这个例子中,将enum构造器声明为private,但对于可访问性没有变化,因此只能在enum定义的内部使用其构造器创建enum实例。当enum的定义结束,编译器不允许在使用其构造器创建任何实例。
- 覆盖enum的方法
覆盖toString()方法,提供了另一种方法来为枚举实例生成不同的字符串描述信息。覆盖enum的toString()方法与覆盖一般类的方法没有区别:
toString()方法通过调用name()方法取得SpaceShip的名字,然后将其修改为只有首字母大写的格式。
switch语句中的enum
一般来说switch中只能使用整数值,而枚举实例天生就具备整数值的次序,因此可以在switch语句中使用enum。
values()的神秘之处
编译器创建的enum类都继承自Enum类,但是Enum类并没有values()方法。利用反射机制编写一个简单的程序,如下例所示:
values()是由编译器添加的static方法,在创建Explore的过程中编译器还为其添加了valueOf()方法。Enum类已经有valueOf()方法了,但是Enum类中的valueOf()方法需要两个参数,而该新增的方法只需要一个参数。由于使用的Set只存储方法的名字而不考虑方法的签名,所以在调用Explore.removeAll(Enum)后,只剩下[values]。
由于values()方法是由编译器插入到enum定义中的static方法,所以如果将enum实例向上转型为Enum,则values()方法不可访问。但是在Class中有一个getEnumConstants()方法,所以即使Enum接口中没有values()方法,我们仍然可以通过Class对象取得所有的enum实例。
由于getEnumConstants()是Class上的方法,因此可以对不是枚举的类调用此方法:
但是此时该方法返回null,因此试图使用其返回的结果会发生异常。
实现,而不是继承
所有的enum都继承自java.lang.Enum类,由于java不支持多重继承,所以enum不能再继承其他类。然而,在创建一个新的enum时,可以同时创建一个或多个接口: