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编程实现,会发现“&”.“|”.“^”这几个逻辑符号竟然可以对数字进行运算.譬如下面的代码就直接对数字分别开展了“与”.“或 ...
随机推荐
- MySQL 中 having 和 where 的区别
区别一: where 是数据从磁盘读入内存时候一条一条判断的 having 是将所有数据读入内存,在分组统计前,根据having的条件再将不符合条件的数据删除 区别二: having 子句可以使用字段 ...
- win10 anaconda安装后使用报错“Original error was: DLL load failed: 找不到指定的模块”
报错:Original error was: DLL load failed: 找不到指定的模块. 环境变量需要添加3个 然后就okay了.
- centos7下搭建高匿HTTP代理
一.一般适用情况1.两台都有外网IP,一台服务器请求资源通过另外一个服务器,本文重点讲第一种.2.两台服务器,其中一台服务器只有内网IP,另外一台服务器有公网和内网IP. 二.前提 # 确认服务器端i ...
- 开启IIS Express可以调试X64项目
//来源:https://blog.csdn.net/ma_jiang/article/details/52679431 现在项目开发时总有时需要在X64下开发,这样我们就需要IIS Express中 ...
- C# WPF 使用委托修改UI控件
近段时间在自学WPF,是一个完全不懂WPF的菜鸟,对于在线程中修改UI控件使用委托做一个记录,给自已以后查询也给需要的参考: 界面只放一个RichTextBox,在窗体启动时开起两个线程,调用两个函数 ...
- monkey 命令详解
monkey命令详解 1. $ adb shell monkey <event-count> <event-count>是随机发送事件数 例 ...
- 脚本语言丨Batch入门教程第四章:调用与传参
今天是Batch入门教程的最后一章内容:调用与传参.相信通过前面的学习,大家已经掌握了Windows Batch有关的基础知识和编程方法,以及利用Windows Batch建立初级的编程思维方式.今后 ...
- [Swift]LeetCode764. 最大加号标志 | Largest Plus Sign
In a 2D grid from (0, 0) to (N-1, N-1), every cell contains a 1, except those cells in the given lis ...
- Tomcat相关面试题,看这篇就够了!保证能让面试官颤抖!
Tomcat相关的面试题出场的几率并不高,正式因为如此,很多人忽略了对Tomcat相关技能的掌握. 这次整理了Tomcat相关的系统架构,介绍了Server.Service.Connector.Con ...
- 微信小程序入门(五)
24.MINA框架讲解 MINA框架架构 25.小程序运行机制 小程序在首次打开的时间会比较长,后续再打开启动会很快,那么小程序是如何启动的呢? 运行机制-启动 冷启动 热启动 热启动:假入用户已经打 ...