一、什么是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相同。