原文地址
翻译地址
概览
在本文中,我们将看到什么是 Java 枚举,它们解决了哪些问题以及如何在实践中使用 Java 枚举实现一些设计模式。
enum关键字在 java5 中引入,表示一种特殊类型的类,其总是继承java.lang.Enum类,更多内容可以自行查看其官方文档。
枚举在很多时候会和常量拿来对比,可能因为本身我们大量实际使用枚举的地方就是为了替代常量。那么这种方式由什么优势呢?
以这种方式定义的常量使代码更具可读性,允许进行编译时检查,预先记录可接受值的列表,并避免由于传入无效值而引起的意外行为。
下面示例定义一个简单的枚举类型 pizza 订单的状态,共有三种 ORDERED, READY, DELIVERED状态:
1 2 3 4 5 6 7
| package shuang.kou.enumdemo.enumtest;
public enum PizzaStatus { ORDERED, READY, DELIVERED; }
|
简单来说,我们通过上面的代码避免了定义常量,我们将所有和 pizza 订单的状态的常量都统一放到了一个枚举类型里面。
1 2 3 4
| System.out.println(PizzaStatus.ORDERED.name()); System.out.println(PizzaStatus.ORDERED); System.out.println(PizzaStatus.ORDERED.name().getClass()); System.out.println(PizzaStatus.ORDERED.getClass());
|
自定义枚举方法
现在我们对枚举是什么以及如何使用它们有了基本的了解,让我们通过在枚举上定义一些额外的API方法,将上一个示例提升到一个新的水平:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| public class Pizza { private PizzaStatus status; public enum PizzaStatus { ORDERED, READY, DELIVERED; }
public boolean isDeliverable() { if (getStatus() == PizzaStatus.READY) { return true; } return false; }
}
|
使用==比较枚举类型
由于枚举类型确保JVM中仅存在一个常量实例,因此我们可以安全地使用“ ==”运算符比较两个变量,如上例所示;此外,“ ==”运算符可提供编译时和运行时的安全性。
首先,让我们看一下以下代码段中的运行时安全性,其中“ ==”运算符用于比较状态,并且如果两个值均为null 都不会引发 NullPointerException。相反,如果使用equals方法,将抛出 NullPointerException:
1 2
| if(testPz.getStatus().equals(Pizza.PizzaStatus.DELIVERED)); if(testPz.getStatus() == Pizza.PizzaStatus.DELIVERED); Copy to clipboardErrorCopied
|
对于编译时安全性,我们看另一个示例,两个不同枚举类型进行比较,使用equal方法比较结果确定为true,因为getStatus方法的枚举值与另一个类型枚举值一致,但逻辑上应该为false。这个问题可以使用==操作符避免。因为编译器会表示类型不兼容错误:
1 2
| if(testPz.getStatus().equals(TestColor.GREEN)); if(testPz.getStatus() == TestColor.GREEN);Copy to clipboardErrorCopied
|
在switch语句中使用枚举类型
1 2 3 4 5 6 7 8
| public int getDeliveryTimeInDays() { switch (status) { case ORDERED: return 5; case READY: return 2; case DELIVERED: return 0; } return 0; }
|
枚举类型的属性,方法和构造函数
你可以通过在枚举类型中定义属性,方法和构造函数让它变得更加强大。
下面,让我们扩展上面的示例,实现从比萨的一个阶段到另一个阶段的过渡,并了解如何摆脱之前使用的if语句和switch语句:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51
| public class Pizza {
private PizzaStatus status; public enum PizzaStatus { ORDERED (5){ @Override public boolean isOrdered() { return true; } }, READY (2){ @Override public boolean isReady() { return true; } }, DELIVERED (0){ @Override public boolean isDelivered() { return true; } };
private int timeToDelivery;
public boolean isOrdered() {return false;}
public boolean isReady() {return false;}
public boolean isDelivered(){return false;}
public int getTimeToDelivery() { return timeToDelivery; }
PizzaStatus (int timeToDelivery) { this.timeToDelivery = timeToDelivery; } }
public boolean isDeliverable() { return this.status.isReady(); }
public void printTimeToDeliver() { System.out.println("Time to delivery is " + this.getStatus().getTimeToDelivery()); }
}
|
下面这段代码展示它是如何 work 的:
1 2 3 4 5 6
| @Test public void givenPizaOrder_whenReady_thenDeliverable() { Pizza testPz = new Pizza(); testPz.setStatus(Pizza.PizzaStatus.READY); assertTrue(testPz.isDeliverable()); }
|