java 枚举应用_Java枚举应用

JDK5.0开始引进了java Enum枚举类型,它可作为我们在编写代码时的一个技巧,有时恰恰因为它,我们能够"优雅而干净"地解决问题。在使用枚举类型时,我们所编写的枚举类都是隐式地继承于java.lang.Enum类,枚举类的每个成员都被隐式声明为public static final,可以通过类名称直接使用它们。

由于枚举类型本质上就是一个类,所以可以在一个独立的文件中来声明枚举值,或者在某个类中声明枚举成员。要定义枚举类型是使用enum关键词。下面就枚举的用法作一个小结:

用法一:提供常量、可用于Switch中

这是它的最基本的用法,把相关的常量定义到一个枚举类型里。

用法二:覆盖枚举的方法

我们可以覆盖枚举的方法,比如toString()方法取得枚举值的字符串描述;values()方法取得所有的枚举成员实例,并以数组方式返回;静态valueOf()方法可以让将指定的字符串尝试转换为枚举类型;使用compareTo()方法比较两个枚举值在枚举时的顺序;使用ordinal()方法得到每个枚举成员在依枚举顺序中的位置索引,默认以0开始。

用法三:构造函数

由于枚举是继承自java.lang.Enum的类,所以也可以定义构造函数,但所定义的函数不能是Public的构造函数。这是为了避免直接实例化枚举类型。注:枚举类中的静态valueOf()方法可以让将指定的字符串尝试转换为枚举类型,如下:

public class EnumClassTest {

enum OrderStatusEnum {

CREATE, PENDING, PICK, PACK, SHIPPING, COMPLETED,

};

public static void main(String[] args) {

for (String s : "CREATE ORDER".split(" ")) {

System.err.println("String is " + s);

if(s.compareTo(OrderStatusEnum.CREATE.toString()) == 0) {

OrderStatusEnum status = Enum.valueOf(OrderStatusEnum.class, s);

System.err.println("s1 == " + status.name()+", value = "+ status.ordinal() + ", " + status.toString());

System.err.println("Order is " + status);

}

}

}

}

运行结果如下:

String is CREATE

s1 == CREATE, value = 0, CREATE

Order is CREATE

String is ORDER

用法四:定义新方法,为每个enum实例赋予各自不同的行为

为每一个枚举实例定义不同的行为,我们可以定义一个或者多个抽象方法作为枚举的一部分,然后为每个枚举实例定义方法。如下:

public enum ConstantSpecificMethod {

DATE_TIME {String getInfo() {

return DateFormat.getDateInstance().format(new Date());

}},

CLASSPATH {String getInfo() {

return System.getenv("CLASSPATH");

}},

VERSION {String getInfo() {

return System.getProperty("java.version");

}};

abstract String getInfo();

public static void main(String[] args) {

for (ConstantSpecificMethod csm : values())

System.out.println(csm.getInfo());

}

}

这种方式我们很方便地使用enum来定义一个简单的状态机应用。

用法五:实现接口定义

由于枚举是继承自java.lang.Enum类,由于Java不支持多继承,所以枚举只能实现接口页不能再继承其他类。

当我们希望扩展枚举的数量或希望对枚举进行分组时,这时就可以通过在接口内定义分组的枚举,然后通过继承这个接口来使用枚举。如下:

enum SecurityCategory {

STOCK(Security.Stock.class), BOND(Security.Bond.class);

Security[] values;

SecurityCategory(Class extends Security> kind) {

values = kind.getEnumConstants();

}

interface Security {

enum Stock implements Security {

SHORT, LONG, MARGIN

}

enum Bond implements Security {

MUNICIPAL, JUNK

}

}

public Security randomSelection() {

return Enums.random(values);

}

public static void main(String[] args) {

for (int i = 0; i < 10; i++) {

SecurityCategory category = Enums.random(SecurityCategory.class);

System.out.println(category + ": " +

category.randomSelection());

}

}

}

用法六:遍历

枚举中的values方法可以获得按枚举定义顺序生成的数组,通过获得枚举中内置的整形顺序,枚举因而被历遍。如下:

public class EnumClassTest {

enum OrderStatusEnum {

CREATE, PENDING, PICK, PACK, SHIPPING, COMPLETED,

};

public static void main(String[] args) {

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

System.err.println(s + " ordinal: " + s.ordinal());

System.err.println(s.compareTo(OrderStatusEnum.CREATE) + " ");

System.err.println(s.equals(OrderStatusEnum.CREATE) + " ");

System.err.println(s == OrderStatusEnum.CREATE);

System.err.println(s.getDeclaringClass());

System.err.println(s.name());

System.err.println("----------------------");

}

}

}

运行结果如下:

CREATE ordinal: 0

0

true

true

class org.jevo.enusample.EnumClassTest$OrderStatusEnum

CREATE

----------------------

PENDING ordinal: 1

1

false

false

class org.jevo.enusample.EnumClassTest$OrderStatusEnum

PENDING

----------------------

PICK ordinal: 2

2

false

false

class org.jevo.enusample.EnumClassTest$OrderStatusEnum

PICK

----------------------

PACK ordinal: 3

3

false

false

class org.jevo.enusample.EnumClassTest$OrderStatusEnum

PACK

----------------------

SHIPPING ordinal: 4

4

false

false

class org.jevo.enusample.EnumClassTest$OrderStatusEnum

SHIPPING

----------------------

COMPLETED ordinal: 5

5

false

false

class org.jevo.enusample.EnumClassTest$OrderStatusEnum

COMPLETED

----------------------

枚举类型的values()方法是编译器插入到enum定义中的static方法,当将enum实例转换成父类Enum类型时,是不能访问values()方法的。但是通过Class的getEnumConstants()方法,仍然可以取得所有的enum实例。如下:

public class EnumClassTest {

enum OrderStatusEnum {

CREATE, PENDING, PICK, PACK, SHIPPING, COMPLETED,

};

public static void main(String[] args) {

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

OrderStatusEnum[] enus = s.getClass().getEnumConstants();

for (OrderStatusEnum s1 : enus) {

System.err.println("enus == " + s1.name()+"");

}

System.err.println("----------------------");

}

}

}

运行结果如下:

enus == CREATE

enus == PENDING

enus == PICK

enus == PACK

enus == SHIPPING

enus == COMPLETED

----------------------

enus == CREATE

enus == PENDING

enus == PICK

enus == PACK

enus == SHIPPING

enus == COMPLETED

----------------------

enus == CREATE

enus == PENDING

enus == PICK

enus == PACK

enus == SHIPPING

enus == COMPLETED

----------------------

enus == CREATE

enus == PENDING

enus == PICK

enus == PACK

enus == SHIPPING

enus == COMPLETED

----------------------

enus == CREATE

enus == PENDING

enus == PICK

enus == PACK

enus == SHIPPING

enus == COMPLETED

----------------------

enus == CREATE

enus == PENDING

enus == PICK

enus == PACK

enus == SHIPPING

enus == COMPLETED

----------------------

用法七:枚举集合的使用

两个枚举集合是 java.util.EnumSet和java.util.EnumMap。EnumSet保证集合中的元素不重复;EnumMap中的key是enum类型,而value则可以是任意类型。但是enum中不能删除添加元素。

Java SE5中EnumSet和EnumMap用于替换基于整型的位标志。位标志通常用来指示某种信息的开关量,但是在代码中是对位进行操作并不是一个有语义的概念,因而不容易被理解。EnumSet的效率比位标志要快,它在内部使用了long来表示一个位向量,然后就可以使用更加概念化的语言来表示某个位的开关,而不用担心效率。注意的是EnumSet中的元素必须来自同一个枚举。如下:

public class EnumSets {

enum AlarmPoints {STAIR1, STAIR2, LOBBY, OFFICE1, OFFICE2, OFFICE3,OFFICE4, BATHROOM, UTILITY, KITCHEN};

public static void main(String[] args) {

EnumSet points1 = EnumSet.allOf(AlarmPoints.class); //所有元素的枚举set

System.err.println(points1);

EnumSet points = EnumSet.noneOf(AlarmPoints.class); //空Set

points.add(AlarmPoints.BATHROOM);

System.err.println(points);

points.addAll(EnumSet.of(AlarmPoints.STAIR1, AlarmPoints.STAIR2, AlarmPoints.KITCHEN));  //包含指定元素的枚举

System.err.println(points);

points = EnumSet.allOf(AlarmPoints.class);

points.removeAll(EnumSet.of(AlarmPoints.STAIR1, AlarmPoints.STAIR2, AlarmPoints.KITCHEN));

System.err.println(points);

points.removeAll(EnumSet.range(AlarmPoints.OFFICE1, AlarmPoints.OFFICE4));//包含两端范围内的所有元素的枚举set

System.err.println(points);

points = EnumSet.complementOf(points); //包含指定 set 中不 包含所有元素

System.err.println(points);

}

}

运行结果如下:

[STAIR1, STAIR2, LOBBY, OFFICE1, OFFICE2, OFFICE3, OFFICE4, BATHROOM, UTILITY, KITCHEN]

[BATHROOM]

[STAIR1, STAIR2, BATHROOM, KITCHEN]

[LOBBY, OFFICE1, OFFICE2, OFFICE3, OFFICE4, BATHROOM, UTILITY]

[LOBBY, BATHROOM, UTILITY]

[STAIR1, STAIR2, OFFICE1, OFFICE2, OFFICE3, OFFICE4, KITCHEN]

使用EnumMap

interface Command {

void action();

}

enum AlarmPoints {STAIR1, STAIR2, LOBBY, OFFICE1, OFFICE2, OFFICE3,OFFICE4, BATHROOM, UTILITY, KITCHEN};

public class EnumMaps {

public static void main(String[] args) {

EnumMap em = new EnumMap(AlarmPoints.class);

em.put(AlarmPoints.KITCHEN, new Command() {

public void action() {

System.err.println("Kitchen fire!");

}

});

em.put(AlarmPoints.BATHROOM, new Command() {

public void action() {

System.err.println("Bathroom alert!");

}

});

for (Map.Entry e : em.entrySet()) {

System.err.println(e.getKey() + ": ");

e.getValue().action();

}

try { // If there's no value for a particular key:

em.get(AlarmPoints.UTILITY).action();

} catch (Exception e) {

System.err.println(e);

}

}

}

运行结果如下:

BATHROOM:

Bathroom alert!

KITCHEN:

Kitchen fire!

java.lang.NullPointerException

综合枚举应用,我们可利用枚举来设计责任链,状态机或多路分发等。

如下是一个处理邮件的实例:

class Mail {

// The NO's lower the probability of random selection:

enum GeneralDelivery {

YES, NO1, NO2, NO3, NO4, NO5

}

enum Scannability {

UNSCANNABLE, YES1, YES2, YES3, YES4

}

enum Readability {

ILLEGIBLE, YES1, YES2, YES3, YES4

}

enum Address {

INCORRECT, OK1, OK2, OK3, OK4, OK5, OK6

}

enum ReturnAddress {

MISSING, OK1, OK2, OK3, OK4, OK5

}

GeneralDelivery generalDelivery;

Scannability scannability;

Readability readability;

Address address;

ReturnAddress returnAddress;

static long counter = 0;

long id = counter++;

public String toString() {

return "Mail " + id;

}

public String details() {

return toString() + ", General Delivery: " + generalDelivery + ", Address Scanability: " + scannability + ", Address Readability: " + readability +

", Address Address: " + address + ", Return address: " + returnAddress;

}

// Generate test Mail:

public static Mail randomMail() {

Mail m = new Mail();

m.generalDelivery = Enums.random(GeneralDelivery.class);

m.scannability = Enums.random(Scannability.class);

m.readability = Enums.random(Readability.class);

m.address = Enums.random(Address.class);

m.returnAddress = Enums.random(ReturnAddress.class);

return m;

}

public static Iterable generator(final int count) {

return new Iterable() {

int n = count;

public Iterator iterator() {

return new Iterator() {

public boolean hasNext() {

return n-- > 0;

}

public Mail next() {

return randomMail();

}

public void remove() { // Not implemented

throw new UnsupportedOperationException();

}

};

}

};

}

}

public class PostOffice {

enum MailHandler {

GENERAL_DELIVERY {

boolean handle(Mail m) {

switch (m.generalDelivery) {

case YES:

System.err.println("Using general delivery for " + m);

return true;

default:

return false;

}

}

},

MACHINE_SCAN {

boolean handle(Mail m) {

switch (m.scannability) {

case UNSCANNABLE:

return false;

default:

switch (m.address) {

case INCORRECT:

return false;

default:

System.err.println("Delivering " + m + " automatically");

return true;

}

}

}

},

VISUAL_INSPECTION {

boolean handle(Mail m) {

switch (m.readability) {

case ILLEGIBLE:

return false;

default:

switch (m.address) {

case INCORRECT:

return false;

default:

System.err.println("Delivering " + m + " normally");

return true;

}

}

}

},

RETURN_TO_SENDER {

boolean handle(Mail m) {

switch (m.returnAddress) {

case MISSING:

return false;

default:

System.err.println("Returning " + m + " to sender");

return true;

}

}

};

abstract boolean handle(Mail m);

}

static void handle(Mail m) {

for (MailHandler handler : MailHandler.values())

if (handler.handle(m))

return;

System.err.println(m + " is a dead letter");

}

public static void main(String[] args) {

for (Mail mail : Mail.generator(10)) {

System.err.println(mail.details());

handle(mail);

System.err.println("*****");

}

}

}

运行结果如下:

Mail 0, General Delivery: NO2, Address Scanability: UNSCANNABLE, Address Readability: YES3, Address Address: OK1, Return address: OK1

Delivering Mail 0 normally

*****

Mail 1, General Delivery: NO5, Address Scanability: YES3, Address Readability: ILLEGIBLE, Address Address: OK5, Return address: OK1

Delivering Mail 1 automatically

*****

Mail 2, General Delivery: YES, Address Scanability: YES3, Address Readability: YES1, Address Address: OK1, Return address: OK5

Using general delivery for Mail 2

*****

Mail 3, General Delivery: NO4, Address Scanability: YES3, Address Readability: YES1, Address Address: INCORRECT, Return address: OK4

Returning Mail 3 to sender

*****

Mail 4, General Delivery: NO4, Address Scanability: UNSCANNABLE, Address Readability: YES1, Address Address: INCORRECT, Return address: OK2

Returning Mail 4 to sender

*****

Mail 5, General Delivery: NO3, Address Scanability: YES1, Address Readability: ILLEGIBLE, Address Address: OK4, Return address: OK2

Delivering Mail 5 automatically

*****

Mail 6, General Delivery: YES, Address Scanability: YES4, Address Readability: ILLEGIBLE, Address Address: OK4, Return address: OK4

Using general delivery for Mail 6

*****

Mail 7, General Delivery: YES, Address Scanability: YES3, Address Readability: YES4, Address Address: OK2, Return address: MISSING

Using general delivery for Mail 7

*****

Mail 8, General Delivery: NO3, Address Scanability: YES1, Address Readability: YES3, Address Address: INCORRECT, Return address: MISSING

Mail 8 is a dead letter

*****

Mail 9, General Delivery: NO1, Address Scanability: UNSCANNABLE, Address Readability: YES2, Address Address: OK1, Return address: OK4

Delivering Mail 9 normally

*****

一个状态机可以根据输入在有限个状态之间移动,然后在满足某种状态之后结束工作,另外每个状态都会有相应的输出,一个售货机器是一个典型的状态机的实例,如下:

enum Input { //售货机可以接收的钞票金额和所有商品的价格

NICKEL(5), //五分

DIME(10), //一角

QUARTER(25), //两角五分

DOLLAR(100),//一块

TOOTHPASTE(200), //药膏2元

CHIPS(75),   //炸薯条75美分

SODA(100),// 苏打水1元

SOAP(50), //肥皂5毛

ABORT_TRANSACTION {

public int amount() {

throw new RuntimeException("退出时不能获取余额!");

}

},

STOP {

public int amount() {

throw new RuntimeException("关机时不能获取余额!");

}

};

//金额

int value;

Input(int value) {

this.value = value;

}

Input() {

}

//返回该操作项的金额

int amount() {

return value;

}

/**

* @return 随机获取的操作

*/

public static Input randomSelection() {

return values()[new Random(System.nanoTime()).nextInt(values().length)];

}

}

enum Category { //自动售货机的状态

MONEY(Input.NICKEL, Input.DIME, Input.QUARTER, Input.DOLLAR), //放入钞票*

ITEM_SELECTION(Input.TOOTHPASTE, Input.CHIPS, Input.SODA, Input.SOAP), //选择商品

QUIT_TRANSACTION(Input.ABORT_TRANSACTION), //退出

SHUT_DOWN(Input.STOP); //关机

private Input[] values;

Category(Input... types) {

values = types;

}

public static EnumMap categories = new EnumMap(Input.class);

public Input[] getValues() {

return values;

}

//初始化自动售货机状态集合

static {

for (Category c : Category.class.getEnumConstants()) {

for (Input input : c.values) {

categories.put(input, c);

}

}

}

/**

* 返回该操作项所属状态*

*/

public static Category categorize(Input input) {

return categories.get(input);

}

}

//自动售货机:VendingMachine用来对输入进行相应,首先通过Category枚举归类输入,然后使用switch语句

public class VendingMachine {

//当前运行状态

private static State state = State.RESTING;

//当前余额

private static int amount = 0;

//当前选择商品

private static Input selection = null;

enum StateDuration { //持续状态,不能做其他操作

TRANSIENT

}

enum State { //运行状态

RESTING {

void next(Input input) {

switch (Category.categorize(input)) {

case MONEY:

amount += input.amount();

System.out.println("放入金额:" + input.amount() + "美分");

state = ADDING_MONEY;

break;

case SHUT_DOWN:

state = TERMINAL;

break;

default:

state = RESTING;

break;

}

}

},

ADDING_MONEY {  //选择商品

void next(Input input) {

switch (Category.categorize(input)) {

case MONEY:

amount += input.amount();

System.out.println("再次放入金额:" + input.amount() + "美分,您的余额是:" + amount + "美分");

break;

case ITEM_SELECTION:

selection = input;

System.out.println("选择商品:" + input);

if (amount < input.amount()) {

System.out.println("你的余额不够购买商品:" + input);

state = ADDING_MONEY;

} else state = DISPENSING;

break;

case QUIT_TRANSACTION:

state = GIVING_CHANGE;

break;

case SHUT_DOWN:

state = TERMINAL;

break;

default:

state = ADDING_MONEY;

break;

}

}

},

DISPENSING(StateDuration.TRANSIENT) { //发出商品,交易成功

void next() {

System.out.println("交易成功!请拿好您的商品:" + selection);

//扣除购买商品的金额

amount -= selection.amount();

state = GIVING_CHANGE;

}

},

GIVING_CHANGE(StateDuration.TRANSIENT) {  //找零

void next() {

if (amount > 0) {

System.out.println("请拿好您的找零:" + amount + "美分");

amount = 0;

}

state = TERMINAL;

}

},

TERMINAL { //交易终止

void output() {

System.out.println("交易结束");

}

};

private boolean isTransient = false;

public boolean isTransient() { //当前是否是瞬时状态(即不可以做其他操作)

return this.isTransient;

}

State() {

}

State(StateDuration stateDuration) {

this.isTransient = true;

}

//默认方法(在瞬时状态时做其他操作时被调用)

void next(Input input) {

System.out.println("该状态不能做其他操作!");

}

//默认方法(在非瞬时状态时不做操作时被调用)

void next() {

System.out.println("请选择一个操作!");

}

//默认方法(查看余额)

void output() {

System.out.println("您的余额还剩:" + amount + "美分");

}

}

//执行一个操作

public static void run(Input gen) {

if (state != State.TERMINAL) {

if (state.isTransient()) {

state.next();

} else {

state.next(gen);

}

} else {

state.output();

}

}

public static void main(String[] args) {

// TODO Auto-generated method stub

int i = 0;

while (true) {

switch (state) {

case RESTING:

run(Enums.random(Category.MONEY.getValues()));

break;

case ADDING_MONEY:

//如果金额不足

if (i > 0) {

run(Enums.random(Category.MONEY.getValues()));

i = 0;

} else {

run(Enums.random(Category.ITEM_SELECTION.getValues()));

i++;

}

break;

case TERMINAL:

run(Input.STOP);

return;

default:

run(null);

break;

}

}

}

}

运行结果如下:

放入金额:25美分

选择商品:CHIPS

你的余额不够购买商品:CHIPS

再次放入金额:25美分,您的余额是:50美分

选择商品:TOOTHPASTE

你的余额不够购买商品:TOOTHPASTE

再次放入金额:5美分,您的余额是:55美分

选择商品:SODA

你的余额不够购买商品:SODA

再次放入金额:5美分,您的余额是:60美分

选择商品:CHIPS

你的余额不够购买商品:CHIPS

再次放入金额:25美分,您的余额是:85美分

选择商品:SODA

你的余额不够购买商品:SODA

再次放入金额:10美分,您的余额是:95美分

选择商品:SOAP

交易成功!请拿好您的商品:SOAP

请拿好您的找零:45美分

交易结束

参考:http://www.jb51.net/article/31951.htm

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值