搜索
写经验 领红包
 > 设计

常量定义是什么(常量的规则)

导语:常量定义也有学问?走过的,路过的,何不进来瞧瞧?

常量定义是什么(常量的规则)

常量声明是每一个项目都不可或缺的,在Java1.5之前,我们只有两种方式的声明:类常量和接口常量,若在项目中使用的是Java1.5之前的版本,基本上都是如此定义的。不过,在1.5版本以后有了改进,即新增了一种常量声明方式:枚举声明常量,看如下代码:

这是一个简单的枚举常量命名,清晰又简单。顺便提一句,JLS(Java Language Specification,Java语言规范)提倡枚举项全部大写,字母之间用下划线分割,这也是从常量的角度考虑的(当然,使用类似类名的命名方式也是比较友好的)。

那么枚举常量与我们经常使用的类常量和静态常量相比有什么优势?问得好,枚举的优点主要表现在四个方面:

1.枚举常量简单:简不简单,我们来对比一下两者的定义和使用情况就知道了。先把Season枚举翻写成接口常量,代码如下:

此处定义了春夏秋冬四个季节,类型都是int,这与Season枚举的排序值是相同的。首先对比一下两者的定义,枚举常量只需定义每个枚举项,不需要定义枚举值,而接口常量(或类常量)则必须定义值,否则编译不通过,即使我们不需要关注其值是多少也必须定义;其次,虽然两者被引用的方式相同(都是 “类名 . 属性”,如Season.SPRING),但是枚举表示的是一个枚举项,字面含义是春天,而接口常量确是一个int类型,虽然其字面含义也是春天,但在运算中我们势必要关注其int值。

2.枚举常量属于稳态型

例如我们要描述一下春夏秋冬是什么样子,使用接口常量应该是这样写。

很简单,先使用switch语句判断哪一个是常量,然后输出。但问题是我们得对输入值进行检查,确定是否越界,如果常量非常庞大,校验输入就成了一件非常麻烦的事情,但这是一个不可逃避的过程,特别是如果我们的校验条件不严格,虽然编译能照样通过,但是运行期就会产生无法预知的后果。

我们再来看看枚举常量是否能够避免校验的问题,代码如下:

不用校验,已经限定了是Season枚举,所以只能是Season类的四个实例,即春夏秋冬4个枚举项,想输入一个int类型或其它类型?门都没有!这是我们最看重枚举的地方:在编译期间限定类型,不允许发生越界的情况。

3.枚举具有内置方法

有一个简单的问题:如果要列出所有的季节常量,如何实现呢?接口常量或类常量可以通过反射来实现,这没错,只是虽然能实现,但会非常繁琐,大家可以自己写一个反射类实现此功能(当然,一个一个地动手打印出输出常量,也可以算是列出)。对于此类问题可以非常简单的解决,代码如下:

通过values方法获得所有的枚举项,然后打印出来即可。如此简单,得益于枚举内置的方法,每个枚举都是java.lang.Enum的子类,该基类提供了诸如获得排序值的ordinal方法、compareTo比较方法等,大大简化了常量的访问。

4.枚举可以自定义的方法

这一点似乎并不是枚举的优点,类常量也可以有自己的方法呀,但关键是枚举常量不仅可以定义静态方法,还可以定义非静态方法,而且还能够从根本上杜绝常量类被实例化。比如我们要在常量定义中获得最舒服季节的方法,使用常量枚举的代码如下: 

我们知道,每个枚举项都是该枚举的一个实例,对于我们的例子来说,也就表示Spring其实是Season的一个实例,Summer也是其中一个实例,那我们在枚举中定义的静态方法既可以在类(也就是枚举Season)中引用,也可以在实例(也就是枚举项Spring、Summer、Autumn、Winter)中引用,看如下代码:

那如果使用类常量要如何实现呢?代码如下:

想想看,我们怎么才能打印出"The most comfortable season is Spring" 这句话呢?除了使用switch和if判断之外没有其它办法了。

虽然枚举在很多方面比接口常量和类常量好用,但是有一点它是比不上接口常量和类常量的,那就是继承,枚举类型是不能继承的,也就是说一个枚举常量定义完毕后,除非修改重构,否则无法做扩展,而接口常量和类常量则可以通过继承进行扩展。但是,一般常量在项目构建时就定义完毕了,很少会出现必须通过扩展才能实现业务逻辑的场景。

注意: 在项目中推荐使用枚举常量代替接口常量或类常量。

本文内容由小苹整理编辑!