Java开发笔记(五十六)利用枚举类型实现高级常量
前面介绍了联合利用final和static可实现常量的定义,该方式用于简单的常量倒还凑合,要是用于复杂的、安全性高的常量,那就力不从心了。例如以下几种情况,final结合static的方式便缺乏应对之策:
1、虽然常量的名称以大写字母拼写,但是对应的取值基本为1、2、3之类的整数,如果把1、2、3直接写在调用的代码里面,岂不是浑水摸鱼顶替了现有的常量蒙混过关?
2、代码可以从常量名推出对应的常量值,可是反过来并不能从常量值推出对应的常量名,开发者晓得不代表程序也晓得。
3、每个常量只有唯一的数值表达,无法表示更丰富的涵义。比如星期一这个常量,可能包括数字“1”、英文单词“Monday”、中文词语“星期一”这些信息组合,然而final联合static的方式只能表达其中一个信息。
听起来似乎言之有理,可是不用整型常量的话,还有什么常量类型能派上用场呢?其实Java语言在设计之初就考虑到了这种情况,在之前的学习当中,已经出现过类似的处理方案。早在介绍本地日期类型LocalDate的时候,提到获取当前月份的办法是调用日期实例的getMonthValue方法,为啥这里不是调用getMonth方法?原来getMonth方法返回的并非整型数值,而是一个Month类型的月份实例,它属于枚举类型。调用该实例的getValue方法,得到的才是月份数字;调用该实例的name方法,可得到大写英文月份的英文单词。先来看看以下的一段月份测试代码:
// 演示Month类型的调用方式。注意,Month类型是Java自带的一种枚举类型
private static void testMonth() {
LocalDate date = LocalDate.now();
Month month = date.getMonth();
System.out.println("month number="+month.getValue()+", month name="+month.name());
}
运行以上的测试代码,观察到如下的日志文本:
month number=12, month name=DECEMBER
根据结果发现getValue方法返回了12,且name方法返回了DECEMBER。从中可见Month类型既包含了月份的数字信息,也包括了月份的英文单词,这正是枚举类型相对于普通常量的优势。
所谓枚举,指的是某些同类型常量的有限集合。Java不但提供了Month这种枚举类型,而且允许程序员自己定义新的枚举类型,如同定义类那样。不同的是,类定义使用class来标识,而枚举类型使用enum来标识。最简单的枚举定义只需一个名称列表,就像以下代码这般:
//演示枚举类型的简单定义
public enum Season {
// 几个枚举变量之间以逗号分隔
SPRING, SUMMER, AUTUMN, WINTER
}
以上代码定义了一种季节枚举Season,它包含了春天SPRING、夏天SUMMER、秋天AUTUMN、冬天WINTER这四个枚举项。四个枚举项既是常量,又都属于Season类型,外部访问它们的格式为“Season.枚举项的名称”。下面是外部访问季节枚举项的代码例子:
// 演示简单枚举类型的调用方式
private static void testEnum() {
Season spring = Season.SPRING; // 声明一个春天的季节实例
Season summer = Season.SUMMER; // 声明一个夏天的季节实例
Season autumn = Season.AUTUMN; // 声明一个秋天的季节实例
Season winter = Season.WINTER; // 声明一个冬天的季节实例
// 枚举类型提供的通用方法主要有两个,
// 其中ordinal方法可获得该枚举的序号,toString可获得该枚举的字段名称
System.out.println("spring number="+spring.ordinal()+", name="+spring.toString());
System.out.println("summer number="+summer.ordinal()+", name="+summer.toString());
System.out.println("autumn number="+autumn.ordinal()+", name="+autumn.toString());
System.out.println("winter number="+winter.ordinal()+", name="+winter.toString());
}
运行上面的测试代码,输出下列的日志信息:
spring number=0, name=SPRING
summer number=1, name=SUMMER
autumn number=2, name=AUTUMN
winter number=3, name=WINTER
结合代码和日志结果,可知枚举项的ordinal方法返回了该枚举所处的序号,toString方法返回了该枚举的常量名称。由于ordinal方法和toString方法是枚举类型enum自带的保留方法,因此无需开发者显式定义即可拿来调用。然而这两个方法毕竟是系统提供的,无法满足丰富多变的个性要求,譬如下列两点需求,简单的枚举类型就无法实现:
1、枚举项的默认序号从0开始计数,但现实生活中很多组合是从1开始计数的。例如一月份对应的数字是1,星期一对应的数字也是1,诸如此类。
2、枚举项的默认名称取的是枚举定义里的列表项名称,但往往更需要中文名称。例如界面上希望展示“春天”而非“SPRING”,希望展示“夏天”而非“SUMMER”,等等。
既然枚举的默认序号与默认名称时常不符合实际情况,这势必要求开发者额外定义新的序号和新的名称。假如说给某个类定义新的属性,那真是易如反掌,可现在待处理的是枚举类型而不是类耶。其实枚举类型enum本来就源自类class,故而完全可以把枚举当作类一样来定义,也就是说,枚举允许定义自己的成员属性、自己的成员方法,乃至自己的构造方法。于是重新定义一个季节枚举,在新的枚举定义中添加序号与名称这两个属性,及其对应的get方法,并补充包含初始化赋值的构造方法。特别注意要在枚举项列表中把每个枚举项都换成携带构造方法的枚举声明,表示该枚举项是由指定构造方法生成的,重写后的季节枚举定义代码示例如下:
//演示枚举类型的扩展定义
public enum SeasonCn {
// 在定义枚举变量的同时,调用该枚举变量的构造方法
SPRING(1,"春天"), SUMMER(2,"夏天"), AUTUMN(3,"秋天"), WINTER(4,"冬天"); private int value; // 定义季节的阿拉伯数字
private String name; // 定义季节的中文名称字段 // 在构造方法中传入该季节的阿拉伯数字和中文名称
private SeasonCn(int value, String name) {
this.value = value;
this.name = name;
} // 获取季节的阿拉伯数字
public int getValue() {
return this.value;
} // 获取季节的中文名称
public String getName() {
return this.name;
}
}
根据新的枚举定义代码,枚举项的序号数值与中文名称如愿换了过来。接着轮到外部调用新的枚举类型,大致流程保持不变,只需将原来的ordinal方法替换为getValue方法,将原来的toString方法替换为getName方法。修改之后的调用代码如下所示:
// 演示扩展枚举类型的调用方式
private static void testEnumCn() {
SeasonCn spring = SeasonCn.SPRING; // 声明一个春天的季节实例
SeasonCn summer = SeasonCn.SUMMER; // 声明一个夏天的季节实例
SeasonCn autumn = SeasonCn.AUTUMN; // 声明一个秋天的季节实例
SeasonCn winter = SeasonCn.WINTER; // 声明一个冬天的季节实例
// 通过扩展而来的getName方法,可获得该枚举预先设定的中文名称
System.out.println("spring number="+spring.getValue()+", name="+spring.getName());
System.out.println("summer number="+summer.getValue()+", name="+summer.getName());
System.out.println("autumn number="+autumn.getValue()+", name="+autumn.getName());
System.out.println("winter number="+winter.getValue()+", name="+winter.getName());
}
运行上述的调用代码,得到以下的日志结果:
spring number=1, name=春天
summer number=2, name=夏天
autumn number=3, name=秋天
winter number=4, name=冬天
由此可见,经过重新编写的SeasonCn枚举,顺利实现了个性化定制序号和名称的目标。
更多Java技术文章参见《Java开发笔记(序)章节目录》
Java开发笔记(五十六)利用枚举类型实现高级常量的更多相关文章
- Java开发笔记(十六)非此即彼的条件分支
前面花了大量篇幅介绍布尔类型及相应的关系运算和逻辑运算,那可不仅仅是为了求真值或假值,更是为了通过布尔值控制流程的走向.在现实生活中,常常需要在岔路口抉择走去何方,往南还是往北,向东还是向西?在Jav ...
- Java开发笔记(十三)利用关系运算符比较大小
前面在<Java开发笔记(九)赋值运算符及其演化>中提到,Java编程中的等号“=”表示赋值操作,并非数学上的等式涵义.Java通过等式符号“==”表示左右两边相等,对应数学的等号“=”: ...
- Java开发笔记(九十六)线程的基本用法
每启动一个程序,操作系统的内存中通常会驻留该程序的一个进程,进程包含了程序的完整代码逻辑.一旦程序退出,进程也就随之结束:反之,一旦强行结束进程,程序也会跟着退出.普通的程序代码是从上往下执行的,遇到 ...
- Java开发学习(三十六)----SpringBoot三种配置文件解析
一. 配置文件格式 我们现在启动服务器默认的端口号是 8080,访问路径可以书写为 http://localhost:8080/books/1 在线上环境我们还是希望将端口号改为 80,这样在访问的时 ...
- Java开发笔记(三十一)字符类型的表达
前面介绍的Java编程,要么是与数字有关的计算,要么是与逻辑有关的推理,充其量只能实现计算器和状态机.若想让Java运用于更广阔的业务领域,就得使其支撑更加血肉丰满的业务场景,而丰满的前提是能够表达大 ...
- Java开发学习(二十六)----SpringMVC返回响应结果
SpringMVC接收到请求和数据后,进行了一些处理,当然这个处理可以是转发给Service,Service层再调用Dao层完成的,不管怎样,处理完以后,都需要将结果告知给用户. 比如:根据用户ID查 ...
- 【Java学习笔记之十六】浅谈Java中的继承与多态
1. 什么是继承,继承的特点? 子类继承父类的特征和行为,使得子类具有父类的各种属性和方法.或子类从父类继承方法,使得子类具有父类相同的行为. 特点:在继承关系中,父类更通用.子类更具体.父类具有更 ...
- Java 学习笔记 执行外部命令 包装类 枚举类型
执行外部命令 Runtime只能通过静态方法getRuntime获得,可以用来执行外部的命令 Runtime runtime = Runtime.getRuntime(); runtime.exec( ...
- Java开发笔记(十五)短路逻辑运算的优势
前面提到逻辑运算只能操作布尔变量,这其实是不严谨的,因为经过Java编程实现,会发现“&”.“|”.“^”这几个逻辑符号竟然可以对数字进行运算.譬如下面的代码就直接对数字分别开展了“与”.“或 ...
随机推荐
- js面向对象和php面向对象的区别
---恢复内容开始--- js的面向对象 1.类 具体相同的特征的一些对象的集合. 2.对象 具体到某一个失误了都可以叫做对象. 3.类 通过function 定义类 所以在js里类的本质是函数, ...
- muse-ui底部导航自定义图标和字体颜色
最近在鼓捣用vue.js进行混合APP开发,遍寻许久终于找到muse-ui这款支持vue的轻量级UI框架,竟还支持按需引入,甚合萝卜意! 底部导航的点击波纹特效也是让我无比惊喜,然而自定义图标和字体颜 ...
- SQL DISTINCT去掉重复的数据统计方法【转】
SELECT指令让我们能够读取表格中一个或数个栏位的所有资料.这将把所有的资料都抓出,无论资料值有无重复.在资料处理中,我们会经常碰到需要找出表格内的不同资料值的情况.换句话说,我们需要知道这个表格/ ...
- [译文]Domain Driven Design Reference(六)—— 提炼战略设计
本书是Eric Evans对他自己写的<领域驱动设计-软件核心复杂性应对之道>的一本字典式的参考书,可用于快速查找<领域驱动设计>中的诸多概念及其简明解释. 其它本系列其它文章 ...
- DDD事件总线的实现
基本思路: (1) 在事件总线内部维护着一个事件与事件处理程序相映射的字典. (2) 利用反射,事件总线会将实现了IEventHandler的处理程序与相应事件关联到一起,相当 ...
- SQL Server Service Broker创建单个数据库会话(消息队列)
概述 SQL Server Service Broker 用来创建用于交换消息的会话.消息在目标和发起方这两个端点之间进行交换.消息用于传输数据和触发消息收到时的处理过程.目标和发起方既可以在同一数据 ...
- [Swift]LeetCode628. 三个数的最大乘积 | Maximum Product of Three Numbers
Given an integer array, find three numbers whose product is maximum and output the maximum product. ...
- [Swift]LeetCode840. 矩阵中的幻方 | Magic Squares In Grid
A 3 x 3 magic square is a 3 x 3 grid filled with distinct numbers from 1 to 9 such that each row, co ...
- Storm学习笔记 - Storm初识
Storm学习笔记 - Storm初识 1. Strom是什么? Storm是一个开源免费的分布式计算框架,可以实时处理大量的数据流. 2. Storm的特点 高性能,低延迟. 分布式:可解决数据量大 ...
- 面试官:说说一条查询sql的执行流程和底层原理?
一条查询SQL执行流程图如下 序章 自我介绍 我是一条sql,就是一条长长的字符串,不要问我长什么样,因为我比较傲娇. 额~~不是我不说啊,因为细说起来,我可以细分为DML(Update.Insert ...