枚举

Java 1.5发行版中增加了两个新的引用类型家族:一种新的类称作枚举类型(enum type),一种新的接口称作注解类型(annotation type)。


>枚举

枚举类型是指由一组固定的常量组成合法值的类型。

  • Java枚举本质上是int值,Java枚举类型背后的基本思想是:它们是通过公有的静态final域为每个枚举常量导出实例的类;
  • 由于没有可访问的构造器,枚举类型是真正的final。客户端既不能创建枚举类型的实例,也不能对它进行扩展,所以很可能没有实例,而只有声明过的枚举常量。它们是实例受控的,是单例(Singleton)的泛型化,本质上是单元素的枚举;
  • Java中,枚举定义了一种类类型,将枚举定义为类,极大地扩展了枚举的概念。在Java中,枚举可以具有构造函数、方法、以及实例变量。

>创建和使用枚举

定义一个简单的enum

enum Apple{
FUJI,PIPPIN,CRANNY_SMITH
}


创建枚举用enum关键字,标识符FUJI、PIPPIN等被称为枚举常量,每个枚举常量被隐式声明为Apple的公有、静态、final成员。枚举常量的类型是声明它们的枚举的类型,如上例代码中是Apple。在Java语言中,这些常量被称为”自类型化的”(sefl-type),其中的”自”指封装常量的枚举。对以上代码编译后会看到编译器将enum类型单独编译成字节码文件Apple.class,使用javap查看

这里写图片描述

定义了枚举后,可以创建枚举类型的变量,然而,虽然枚举定义了类类型,却不用new实例化枚举,枚举变量的使用方式很大程度上与基本类型相同。获取Apple枚举类的一个实例:

Apple a = Apple.FUJI;

>构造器

枚举类是class,在枚举类型中有构造器、方法、数据域。枚举类的构造器是在构造枚举常量的时候被调用。 每个枚举常量都是所属枚举类型的对象。如果为枚举定义了构造函数,当创建每个枚举常量是都会调用该构造函数。对于枚举定义的实例变量,每个枚举常量都有它自己的副本。
代码示例

package com.afy.enumdemo;

enum Apple{
    Jonathan(10), GoldenDel(9),RedDel(12),Winesap(15),Cortland(8);

    private int price;     //price of each apple

    //Constructor
    private Apple(int p) {
        price = p;
    }

    int getPrice(){
        return price;
    }
}

class AppleEnumDemo {

    public static void main(String[] args) {
        Apple ap;

        //Display price of Winesap.
        System.out.println("Winesap costs" + Apple.Winesap.getPrice() + "cents.\n");

        //Display all apples and prices.
        System.out.println("All apple price:");
        for(Apple a : Apple.values())
            System.out.println(a + "cost" + a.getPrice() + "cents.");
    }

}

这段代码中有实例变量price,有Apple构造函数,有getprice()方法。每个常量后面圆括号中的数值是指定构造函数参数,这些数值被传递给Apple()方法的参数p,然后将这些值赋给price变量.当在main()方法中声明变量ap时,对于每个特定的常量调用Apple的构造函数一次

每个枚举变量都由自己的price变量副本,可以调用getPrice()方法来获取指定类型苹果的价格,若获取Cortland的价格:

Apple.Cortland.getPrice()

也可以通过for循环获取所有品种的苹果价格。由于每个枚举常量都有price变量的副本,所以与枚举常量关联的值是独立的,并且和与其他常量关联的值不同。将枚举作为类实现像Java一样,才有这样强大的功能。

针对构造器,就像其他类一样,枚举提供多种重载形式。可以将price变量初始化为-1.表明不能获得价格数据:

//Use an enum constructor.
enum Apple{
  Jonathan(10),GoldenDel(9),RedDel,Winesap(15),Cortland(8);

  private int price;  //price of each apple

  //Constructor
  Apple(int p){
     price = p;
  }

  //Overloaded constructor
  Apple(){
    price = -1;
 }

 int getPrice(){
 return price;
 }
}

这里没有给RedDel赋参数,这样会调用默认构造函数,并将RedDel的price变量设置为-1。

构造器只能使用私有private访问控制符,而不应有public构造器,以保证外部代码无法新构造枚举类的实例,我们已知道枚举常量是public static final的常量,即枚举对象的属性不应允许改动。然而枚举类的方法和数据域允许外部访问。

枚举switch的语句用法

枚举值可以用于控制switch语句,可以在switch表达式中使用Enum定义的枚举类的对象作为表达式,case子句可以直接使用枚举值的名字,枚举常量的名称没有使用枚举类型的名称进行限定,如直接用Jonathan,而不用Apple.Jonathan,因为switch表达式中的枚举类型已经隐式指定了case常量的枚举类型,故不使用枚举类型的名称对常量进行限定,而如果这样试图这么做的话,会造成编译时错误。如

System.out.println(Apple.Jonathan);

这样做打出“Jonathan”。

示例代码

package com.afy.enumdemo;

enum Apple1 {
    Jonathan,GoldenDel,RedDel,Winesap,Cortland
}

class EnumSwitchDemo {
    public static void main(String[] args) {
        Apple1 ap ;

        ap = Apple1.RedDel;

        //OUtput an enum value.
        System.out.println("value of ap is: " + ap);
        System.out.println();

        ap = Apple1.GoldenDel;

        //compare two enum values
        if (ap==Apple1.GoldenDel) {
            System.out.println("ap contains GoldenDel.\n");         
        }

        //Use an enum to control a switch statement,
        switch (ap) {
        case Jonathan:
            System.out.println("Jonathan is red");
            break;

        case GoldenDel:
            System.out.println("Golden delicios is yellow");
            break;

        case RedDel:
            System.out.println("Red Delicious is red");
            break;
        case Winesap:
            System.out.println("Winesap is red");
            break;
        case Cortland:
            System.out.println("Cortland is red");
            break;
        }
    }
}


values()和valueOf()方法

所有枚举都自动包含两个预定义方法:values()和valueOf()。它们的一般形式如下:
public static enum-type [] values()
public static enum-type [] valueOf(String str)


values()方法返回一个包含枚举常量列表的数组,valueOf()方法返回与传递到参数str的字符串相对应的枚举常量。enum-type是枚举类型,如Apple枚举,Apple.vallueOf(“Winesap”)返回的是Winesap。

代码示例

package com.afy.enumdemo;

enum Apple2{
    Jonathan,GoldenDel,RedDel,Winesap,Cortland
}

public class ValuesAndValueOfDeme {
    public static void main(String[] args) {
        Apple ap;

        System.out.println("Here are all Apple constants:");

        //use values()
        Apple allapples[] = Apple.values();
        for (Apple a : allapples) {
            System.out.println(a);
        }

        System.out.println();

        //use valueOf()
        ap = Apple.valueOf("Winesap");
        System.out.println("ap contains " + ap);
    }
}


这里使用for-each风格的for循环来遍历values()方法返回的常量数组。为了进行说明,创建变量allapples,并将其赋值为对枚举数组的引用,但不一定要这样,可以如下:

for(Apple a : Apple.values())
  System.out.println(a);


枚举的限制

1. 枚举不能继承其他类;
2. 枚举不能是超类,这意味着枚举不能扩展;

除此之外,枚举与其他类相似,尤其要注意的是:每个枚举常量都是定义它的类的对象。

>枚举都继承Enum类

尽管声明枚举时不能继承超类,但是

这里写图片描述

java.lang.Enum这个类定义了所有枚举都可以使用的一些方法。

这里写图片描述

>枚举实现接口

枚举和Java其他类一样,可以实现一个或多个接口。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章