枚举
来源:互联网 发布:小说书籍知乎 编辑:程序博客网 时间:2024/06/14 05:53
不要让这个世界的复杂性阻碍你的前进。 要成为一个行动主义者,将解决人类的不平等视为己任。 它将成为你生命中最重要的经历之一。
——比尔·盖茨在哈佛大学的演讲
声明枚举
[public]enum 枚举类型名称[implements 接口名称列表]{ 枚举值; 变量成员声明及初始化; 方法声明及方法体;}
简单的例子:
/** * 简单的枚举类型举例 * @author wangbaofu * */public class ScoreTester { public static void main(String[] args) { giveScore(Score.EXCELLENT); } private static void giveScore(Score s) { switch (s) { case EXCELLENT: System.out.println("Excellent"); break; case QUALIFIED: System.out.println("Qualified"); break; case FAILED: System.out.println("Failed"); break; default: break; } }}enum Score { EXCELLENT, QUALIFIED, FAILED;}/* * 输出 Excellent * */
枚举的特点:
- 枚举定义实际上是定义了一个类
- 所有枚举类型都隐含继承(扩展)自Java.lang.Enum,因此枚举类型不能再继承任何其它类
- 枚举类型中的类可以包括方法和变量
- 枚举类型的构造方法必须是包内私有或者私有的。定义在枚举开头的常量会自动创建,不能显示地调用枚举类的构造方法。
枚举类型的默认方法
- 静态的values()方法用于获得枚举类型的枚举值的数组
- toString方法返回枚举值的字符串描述
- valueOf方法将以字符串形式表示的枚举值转化为枚举类型的对象
- Ordinal方法获得对象在枚举类型中的位置索引
最佳实践 (该部分内容为《编写高质量代码之java》学习笔记)
推荐使用枚举定义常量
常量声明是每一个项目都不可或缺的,在Java 1.5之前,
我们只有两种方式的声明:类常量和接口常量,若在项目中
使用的是Java 1.5之前的版本基本上都是如此定义的。不过,
在1.5版以后有了改进,即新增了一种常量声明方式: 枚举声明常量。
枚举声明常量的优点
(1)枚举常量更简单
(2)枚举常量属于稳态型
(3)枚举具有内置方法
是java.lang.Enum的子类,该基类提供了诸如获得排序值的ordinal方法、compareTo比较方法等,大大简化了常量的访问。
(4)枚举可以自定义方法
举常量不仅可以定义静态方法,还可以定义非静态方法,而且还能够从根本上杜绝常量类被实例化。
package enumtest;/** * 枚举的优势 * */public class TestSeason { public static void main(String[] args) {// 通过values方法获得所有的枚举项 for (Season s : Season.values()) { System.out.println(s); } }}enum Season{ Spring,Summer,Autumn,Winter;}interface SeasonIntece{ int Spring=0; int Summer=1; int Autumn=2; int Winter=3;}
使用构造函数协助描述枚举项
枚举的属性:排序号,其默认值为0,1,2,3…
枚举描述:含义通过枚举的构造函数,声明每个枚举项(也就是枚举的实例)
必须具有属性和行为,这是对枚举的描述和补充,目的是使,枚举项表述的意义更加清晰准确
enum Season { Spring("春"), Summer("夏"), Autumn("秋"), Winter("冬");
private String desc; Season(String desc) { this.desc = desc; } // 自定义方法 public static Season getComfortableSeason() { return Spring; }//获取枚举描述 public String getDesc() { return desc; }}
小心switch带来的空值异常,处理方法增加空判断
对于枚举类型很多的情况下,在default中添加: throw
new AssertionError(“没有该类型”);
使用valueOf前必须进行校验
package enumtest;import java.util.Arrays;import java.util.List;public class ValueOfTest { public static void main(String[] args) { List<String> params = Arrays.asList("EXCELLENT", "aDD"); for (String name : params) { // 查找直面值与name相同的枚举 项// 添加代码 if(Score.contains(name)){ Score s = Score.valueOf(name); if (s != null) { // 有该枚举项时 System.out.println(s); } else { // 没有该枚举项时 System.out.println("无相关枚举项"); } } // Score s = Score.valueOf(name);// if (s != null) {// // 有该枚举项时// System.out.println(s);// } else {// // 没有该枚举项时// System.out.println("无相关枚举项");// } } } enum Score { EXCELLENT, QUALIFIED, FAILED, ADD; // 是否包含枚举项 public static boolean contains(String name) { // 所有的枚举值 Score[] scores = values(); // 遍历查找 for (Score s : scores) { if (s.name().equals(name)) return true; } return false; } }}/* * Exception in thread "main" java.lang.IllegalArgumentException: No enum * constant enumtest.ValueOfTest.Score.aDD * * public static<T extends Enum<T>>T valueOf(Class<T>enumType, String name){ * //通过反射,从常量列表中查找 T result=enumType.enumConstantDirectory().get(name); * if(result!=null) return result; if(name==null) throw new * NullPointerException("Name is null"); //最后排除无效参数异常 throw new * IllegalArgumentException("No enum const"+enumType+"."+name); } */
(1) 枚举非静态方法实现工厂方法模式
用枚举实现工厂方法模式更简洁
package enumtest;/** * 工厂方法模式(Factory Method Pattern)是“创建对象的接口,让子类决定实例化哪一个类,并使一个类的实例化延迟到其子类”。 * 工厂方法模式在我们的开发工作中经常会用到。 * 这是最原始的工厂方法模式,有两个产品:福特汽车和别克汽车,然后通过工厂方法模式来生产。有了工厂方法模式,我们就不用关心一辆车具体是怎么生成的了 * ,只要告诉工厂“给我生产一辆福特汽车”就可以了 */// 抽象产品interface Car {};// 具体产品类class FordCar implements Car {};// 具体产品类class BuickCar implements Car {};// 工厂类public class CarFactory { public static Car createCar(Class<? extends Car> c) { try { return c.newInstance(); } catch (InstantiationException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } return null; } public static void main(String[] args) {// 生产车辆 Car cat =CarFactory.createCar(FordCar.class); }}
package enumtest;//枚举非静态方法实现工厂方法模式public class CarFactoryEnum { public static void main(String[] args) {// 生产汽车 Car car = CarFactoryEnum1.BuickCar.create(); }}enum CarFactoryEnum1 { // 定义工厂类能生产汽车的类型 FordCar, BuickCar; // 生产汽车 public Car create() { switch (this) { case FordCar: return new FordCar(); case BuickCar: return new BuickCar(); default: throw new AssertionError("无效参数"); } }}
(2)通过抽象方法生成产品
enum CarFactory3{ FordCar{ public Car create(){ return new FordCar(); } },BuickCar{ public Car create(){ return new BuickCar(); } };// 首先定义一个抽象制造方法create,然后每个枚举项自行实现。 public abstract Car create();}
用枚举类型的工厂方法模式有以下三个优点:
(1)避免错误调用的发生
(2)性能好,使用便捷
枚举类型的计算是以int类型的计算为基础的,这是最基本的操作,性能当
然会快,至于使用便捷,注意看客户端的调用,代码的字面意思就是“汽车
工厂,我要一辆别克汽车,赶快生产”。
(3)降低类间耦合
不管生产方法接收的是Class、String还是int的参数,都会成为客户端类的
负担,这些类并不是客户端需要的,而是因为工厂方法的限制必须输入的,
例如Class参数,对客户端main方法来说,它需要传递一个FordCar.class
参数才能生产一辆福特汽车,除了在create方法中传递该参数外,业务类
不需要改Car的实现类。这严重违背了迪米特原则(Law of Demeter,简称为LoD),也就是最少知识原则:一个对象应该对其他对象有最少的了解。
示例代码
/** * 支付类型 */ public enum PayType{ typeUnknow("未知支付类型" , -1), typeAlipay("支付宝支付" , 4), typeWechatPay("微信支付" , 5); private String name; private int value; // 构造方法 private PayType(String name, int value) { this.name = name; this.value = value; } }