[Java 基础]枚举

概念

枚举(enum)是一个被命名的整型常量的集合。

enum相对于普通常量最明显的好处在于更有组织性。

尽管enum看起来像是一种新的数据类型,事实上,enum是一种受限制的类,并且具有自己的方法。

创建enum时,编译器会为你生成一个相关的类,这个类继承自java.lang.Enum

java.lang.Enum类声明

public abstract class Enum<E extends Enum<E>>

        implements Comparable<E>, Serializable {}

 

enum基本特性

enum中,提供了一些基本方法:

values()返回enum实例的数组,而且该数组中的元素严格保持在enum中声明时的顺序。

name()返回实例名。

ordinal()返回实例声明时的次序,从0开始。

getDeclaringClass()返回实例所属的enum类型。

可以使用==来比较enum实例,编译器会自动提供equals()hashCode()方法。此外,java.lang.Enum实现了ComparableSerializable接口,所以也提供compareTo()方法。

例:展示enum的基本特性

注:有个小细节,如果枚举中没有定义方法,可以在最后一个实例后面加逗号或分号或什么符号都不加

enum Color {

    RED, GREEN, BLUE

    // 如果枚举中没有定义方法,也可以在最后一个实例后面加逗号或分号

    // RED, GREEN, BLUE,

    // RED, GREEN, BLUE;

};

 

public class EnumDemo {

    public static void main(String args[]) {

        for (Color c : Color.values()) {

            System.out.println(c + " ordinal: " + c.ordinal());

            System.out.print(c.compareTo(Color.GREEN) + " ");

            System.out.print(c.equals(Color.GREEN) + " ");

            System.out.println(c == Color.GREEN);

            System.out.println(c.getDeclaringClass());

            System.out.println(c.name());

            System.out.println("===================================");

 }

    }

};

输出:

RED ordinal: 0

-1 false false

class com.notes.enumeration.Color

RED

===================================

GREEN ordinal: 1

0 true true

class com.notes.enumeration.Color

GREEN

===================================

BLUE ordinal: 2

1 false false

class com.notes.enumeration.Color

BLUE

===================================

 

enum具有类的特性

enum不能为实例赋值

CC++语言中的enum,可以为实例直接赋值,但是Java不能用“=”为enum实例赋值

例:CC++语言中的enum初始化

#include "stdafx.h"

#include <iostream>

using namespace std;

typedef enum{

    ONE = 1,

    TWO,

    THREE = 3,

    TEN = 10

} Number;

 

int _tmain(int argc, _TCHAR* argv[])

{

    cout << Number::ONE << endl;

    cout << Number::TWO << endl;

    cout << Number::THREE << endl;

    cout << Number::TEN << endl;

    return 0;

}

输出:

1

2

3

10

 

添加方法

Java虽然不能直接为实例赋值,但是它有更优秀的解决方案:为enum添加方法。

除了不能继承自一个enum外,基本上可以将enum看做一个常规的类(因为enum都继承自类,且Java不支持多重继承,所以enum不能再继承其他类)。

创建新的enum时,可以为其添加多种方法,甚至可以为其添加构造方法。

注意一个细节:如果要为enum定义方法,那么必须在enum的最后一个实例尾部添加一个分号。此外,在enum中,必须先定义实例,不能将字段或方法定义在实例前面。否则,编译器会报错。

例:列举一个错误码的枚举,全面展示如何在枚举中定义普通方法、静态方法、抽象方法、构造方法

public enum ErrorCode {

    OK(0) {

        public String getName() {

            return "成功";

        }

    },

    ERROR_A(100) {

        public String getName() {

            return "错误A";

        }

    },

    ERROR_B(200) {

        public String getName() {

            return "错误B";

        }

    };

 

    private ErrorCode(int number) { // 构造方法

        this.number = number;

    }

 

    private int number;

    public int getNumber() { // 普通方法

        return number;

    }

 

    public abstract String getName(); // 抽象方法

 

    public static String getAll() { // 静态方法

        String result = "[";

        for(ErrorCode code : ErrorCode.values()){

            result += code.getName() + ", ";

        }

        result += "]";

        return result;

    }

    public static void main(String args[]) {

        System.out.println("getAll: " + ErrorCode.getAll());

        for (ErrorCode s : ErrorCode.values()) {

            System.out.println("name: " + s.getName() + ", number: " + s.getNumber());

        }

    }

}

在上例中,刻意将构造方法声明为private,但对于它的可访问性而言,没有什么变化。因为我们只能在enum的内部使用构造器来创建enum实例。一旦enum结束定义,编译器就不允许我们再使用构造器来创建任何实例了。事实上,enum的构造器只能被声明为private权限或不声明权限

输出:

getAll: [成功, 错误A, 错误B, ]

name: 成功, number: 0

name: 错误A, number: 100

name: 错误B, number: 200

 

覆写方法

创建新的enum时,允许覆写java.lang.Enum中的方法

例:覆写toString()方法

enum Signal {

    RED, GREEN, YELLOW;

    public String toString() {

        return "覆写toString()方法";

    }

   

    public static void main(String args[]) {

        System.out.println("toString: " + Signal.RED.toString());

    }

};

输出:

toString: 覆写toString()方法

 

 

实现接口

创建新的enum时,可以实现一个或多个接口。

实现了接口的enum类型,也可以像普通类一样做向上转型为它所实现的接口。这样的好处在于,有利于组织代码。

例:FruitAnimal都实现了Print接口,可以像普通类一样做向上转型为Print

interface Print {

    public String getName();

}

 

enum Fruit implements Print {

    Apple {

        public String getName() {

            return "苹果";

        }

    },

    Orange {

        public String getName() {

            return "橘子";

        }

    },

    PEAR {

        public String getName() {

            return "梨子";

        }

    };

}

 

enum Animal implements Print {

    Dog {

        public String getName() {

            return "";

        }

    },

    Cat {

        public String getName() {

            return "";

        }

    },

    Bird {

        public String getName() {

            return "";

        }

    };

}

 

public class InterfaceEnumDemo {

    public static void main(String args[]) {

        // FruitAnimal都实现了Print接口,可以像普通类一样做向上转型为Print

        for (Print p : Fruit.values()) {

            System.out.print(p.getName() + " ");

        }

 

        System.out.println();

        for (Print p : Animal.values()) {

            System.out.print(p.getName() + " ");

        }

    }

};

 

enumswitch组成状态机

enumswitch的关系就像是方糖之于咖啡。

swtich中只能使用整型值,而枚举实例天生就具备整数值的次序,所以二者常常被组合使用来实现状态机。

例:

enum Signal {

    RED, GREEN, YELLOW

};

 

public class TrafficLight {

    public static String getState(Signal signal) {

        String state = null;

        switch (signal) {

            case RED:

                state = "红灯停";

                break;

            case GREEN:

                state = "绿灯行";

                break;

            case YELLOW:

                state = "黄灯要小心";

                break;

            default:

                state = "异常";

                break;

        }

        return state;

    }

 

    public static void main(String args[]) {

        System.out.println("state: " + TrafficLight.getState(Signal.GREEN));

    }

}

输出:

state: 绿灯行


你可能感兴趣的:([Java 基础]枚举)