您的位置:

Java枚举详解

一、什么是Java枚举

Java中的枚举(enum)是一种特殊的类,它表示了一个固定数量的常量。这些常量是预定义的,不能被修改。相对于使用常量,枚举提供了更好的可读性和类型安全性,它可以定义一系列有关联的常量,并为这些常量指定一个专用的类型。

在Java 5之前,常量被定义为int或String常量实际上是非常普遍的。这样很容易出错,常量值不能被限制在定义的范围内,也很难调试错误。此外,由于没有一种类型来表示常量,因此通常使用魔法数字。当需要使用常量时,需要手动查找和输入这些魔法数字,导致代码不够直观。

与常量相比,枚举类型更为强大。枚举类型不仅可以包含常量值,还可以包含任意的属性、方法和构造函数。

二、定义一个枚举类型

枚举类型的定义是在类的内部,它可以包含一组常量、属性和方法。例如,定义一个枚举类型来表示一周中的一天:

public enum Day {
    MONDAY, TUESDAY, WEDNESDAY, THURSDAY,
    FRIDAY, SATURDAY, SUNDAY
}

枚举类型Day包含七个常量:MONDAY、TUESDAY、WEDNESDAY、THURSDAY、FRIDAY、SATURDAY和SUNDAY。这些常量按照枚举类型的声明顺序依次编号为0到6。如果需要访问枚举类型中定义的常量,可以直接使用Day.MONDAY、Day.TUESDAY等语法来引用它们。

每个枚举常量都是Day类型的一个实例,public static final修饰符可以保证它们是不可修改的。在枚举类型中,它们是被视为这个类型的实例的。

三、枚举类型的属性和方法

1. 枚举属性

与Java类类似,枚举常量可以包含任意的属性。例如,为Day枚举类型添加一个星期几名称的属性:

public enum Day {
    MONDAY("星期一"), TUESDAY("星期二"), WEDNESDAY("星期三"),
    THURSDAY("星期四"), FRIDAY("星期五"), SATURDAY("星期六"), SUNDAY("星期日");
    
    private String name;

    Day(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }
}

在这个例子中,声明了一个名称为name的私有属性和一个名为getName()的公有方法。这个方法返回在枚举类型定义中指定的星期几名称。可以通过Day.MONDAY.getName()等语法访问这个属性。

2. 枚举方法

枚举类型还可以包含方法,这些方法可以被所有枚举常量共享。例如,添加一种方法来检查某一天是否是工作日:

public enum Day {
    MONDAY("星期一"), TUESDAY("星期二"), WEDNESDAY("星期三"),
    THURSDAY("星期四"), FRIDAY("星期五"), SATURDAY("星期六"), SUNDAY("星期日");
    
    private String name;

    Day(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }

    public boolean isWeekday() {
        return !this.equals(SATURDAY) && !this.equals(SUNDAY);
    }
}

在这个例子中,声明了一个名为isWeekday()的方法,它检查这个枚举类型表示的是否为工作日(星期一到星期五),如果是则返回true,否则返回false。

四、switch语句和枚举

在Java中,可以使用switch语句来实现多个分支。switch语句可以用于枚举类型。

public void doSomething(Day day) {
    switch(day) {
        case MONDAY:
            System.out.println("星期一");
            break;
        case TUESDAY:
            System.out.println("星期二");
            break;
        case WEDNESDAY:
            System.out.println("星期三");
            break;
        case THURSDAY:
            System.out.println("星期四");
            break;
        case FRIDAY:
            System.out.println("星期五");
            break;
        case SATURDAY:
            System.out.println("星期六");
            break;
        case SUNDAY:
            System.out.println("星期日");
            break;
        default:
            System.out.println("无效的日子");
            break;
    }
}

doSomething()方法接受一个Day类型的参数,并且拥有一个处理Day类型参数的switch语句。默认情况下,switch语句执行default分支。

五、枚举类型的高级用法

1. 实现接口

与Java类一样,枚举类型也可以实现接口,例如:

public interface MyInterface {
    public void doSomething();
}

public enum MyEnum implements MyInterface {
    ONE, TWO, THREE;

    public void doSomething() {
        System.out.println("do something");
    }
}

在这个例子中,MyEnum枚举实现了MyInterface接口,并重写了它的doSomething()方法。如果需要使用这个方法,可以通过MyEnum.ONE.doSomething()等语法来调用它。

2. 实现抽象方法

枚举类型也可以像Java类一样定义抽象方法,在枚举常量中实现这个方法。例如:

public enum Operation {
    PLUS {
        public double apply(double x, double y) {
            return x + y;
        }
    },
    MINUS {
        public double apply(double x, double y) {
            return x - y;
        }
    },
    TIMES {
        public double apply(double x, double y) {
            return x * y;
        }
    },
    DIVIDE {
        public double apply(double x, double y) {
            return x / y;
        }
    };

    public abstract double apply(double x, double y);
}

在这个例子中,Operation枚举类型包含四个常量:PLUS、MINUS、TIMES和DIVIDE。每个常量都实现了一个apply()方法来表示不同的操作。apply()方法具有抽象类型,在枚举类型定义中,它被重写以实现指定的操作。

3. 序列化和枚举

Java的序列化机制用于将对象转换为字节序列的过程,以便将对象存储到磁盘或通过网络发送。Java中的枚举类型是天生可序列化的,可以直接序列化和反序列化。可以使用ObjectInputStream和ObjectOutputStream对枚举类型进行序列化和反序列化。

public class EnumTest {
    public static void main(String[] args) {
        ObjectOutputStream oos = null;
        ObjectInputStream ois = null;
        try {
            oos = new ObjectOutputStream(new FileOutputStream("test.obj"));
            oos.writeObject(MyEnum.ONE);
            oos.flush();

            ois = new ObjectInputStream(new FileInputStream("test.obj"));
            MyEnum myEnum = (MyEnum) ois.readObject();
            System.out.println(myEnum == MyEnum.ONE);
        } catch (IOException | ClassNotFoundException e) {
            e.printStackTrace();
        } finally {
            try {
                if (ois != null) {
                    ois.close();
                }
                if (oos != null) {
                    oos.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

在这个例子中,创建了一个MyEnum类型的常量ONE,并将它写入了一个名为test.obj的文件中。然后从test.obj文件中读取对象,并将它赋值给一个MyEnum类型的变量。最后测试对象是否与常量ONE相同。