12.1.3 Java枚举是类类型
正如前面所解释的,Java枚举是类类型。虽然不能使用new实例化枚举,但是枚举却有许多和其他类相同的功能。实际上,枚举定义了为Java枚举提供功能的类,这些功能是其他语言中的枚举所不具备的。例如,可以为枚举提供构造函数、添加实例变量和方法,甚至可以实现接口。
需要理解的重要一点是:每个枚举常量都是所属枚举类型的对象。因此,如果为枚举定义了构造函数,那么当创建每个枚举常量时都会调用该构造函数。此外,对于枚举定义的实例变量,每个枚举常量都有它自己的副本。例如,分析下面版本的Apple枚举:
这个版本的Apple枚举添加了3个内容:第1个内容是实例变量price,用于保存每种苹果的价格;第2个内容是Apple构造函数,用于传递苹果的价格,第3个内容是getPrice()方法,用于返回price变量的值。
当在main()方法中声明变量ap时,对于每个特定的常量调用Apple的构造函数一次。注意指定构造函数参数的方式,通过将它们放置到每个常量后面的圆括号中来加以指定,如下所示:
- Jonathan(10), GoldenDel(9), RedDel(12), Winesap(15), Cortland(8);
这些数值被传递给Apple()方法的参数p,然后将这些值赋给price变量。再强调一次,为每个常量调用构造函数一次。
因为每个枚举常量都有自己的price变量副本,所以可以调用getPrice()方法来获取指定类型苹果的价格。例如在main()方法中,通过下面的调用获取Winesap的价格:
- Apple.Winesap.getPrice( )
通过for循环遍历枚举可以获取所有品种的苹果的价格。因为每个枚举常量都有price变量的副本,所以与枚举常量关联的值是独立的,并且和与其他常量关联的值不同。这是一个强大的功能,只有将枚举作为类实现,像Java这样,才会具有这种功能。
尽管前面的例子只包含一个构造函数,但是枚举可以提供两种甚至更多种重载形式,就像其他类那样。例如,下面版本的Apple提供了一个默认构造函数,可以将price变量初始化为.1,表明不能获得价格数据:
注意在这个版本中,没有为RedDel提供参数。这意味着会调用默认构造函数,并将RedDel的price变量设置为−1。
枚举有两条限制:第一,枚举不能继承其他类;第二,枚举不能是超类。这意味着枚举不能扩展。在其他方面,枚举和其他类很相似。需要记住的关键是:每个枚举常量都是定义它的类的对象。