热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

EffectiveJava用enum代替int常量

在java1.5之前,表示枚举类型的常用模式是声明一组具名的int常量,每个类型成员一个常量:publicstaticfinalintAP

在java1.5之前,表示枚举类型的常用模式是声明一组具名的int常量,每个类型成员一个常量:

public static final int APPLE_FUJI = 0;
public static final int APPLE_PIPPIN = 1;
public static final int APPLE_GRANNY_SMITH = 2;public static final int ORANGE_NAVEL = 0;
public static final int ORANGE_TEMPLE = 1;
public static final int ORANGE_BLOOD = 2;

缺点:

1.将apple传到想要orange的方法中,不会出现错误

2.用==操作符将apple与orange比较,不会出现错误

3.int枚举是编译时常量,被编译到客户端中,如果枚举常量关联的int发生变化,客户端必须重新编译,如果没有重新编译,程序仍可以运行,但行为就确定了,如APPLE_FUJI关联的常量不再是0,而是3。

4.将int枚举常量翻译成可打印的字符串很麻烦

5.遍历一个组中所有的int枚举常量,获得int枚举组的大小,没有可靠的方法,如想知道APPLE的常量有多少个,除了查看int枚举常量所在位置的代码外,别无他法,而且靠的是观察APPLE_前缀有多少个,不可靠

 

枚举类型是int枚举常量的替代解决方案:

public enum Apple {FUJI, PIPPIN, GRANNY_SMITH}
public enum Orange {NAVEL, TEMPLE, BLOOD}

枚举是功能齐全的类,通过公有的静态final域为每个枚举常量导出实例的域。因为没有可以可以访问的构造器,客户端不能创建枚举类型的实例,也不能扩展它。

枚举提供编译时的类型安全,如果一个参数的类型是Apple,就可以保证,被传入到该参数上的任何非null对象引用一定是FUJI,PIPPIN,GRANNY_SMITH三个之一。

包含同名常量的多个枚举类型可以共存,因为每个类型有自己的命名空间,增加或重新排列枚举类型的常量,无需重新编译客户端代码。

通过调用toString方法,可以将枚举转换成可打印的字符串。

 

枚举类型有方法和域:

public enum Planet {MERCURY(3.302e+23, 2.439e6),VENUS(4.869e+24, 6.052e6),EARTH(5.975e+24, 6.378e6),MARS(6.419e+23, 3.393e6),JUPITER(1.899e+27, 7.149e7),SATURN(5.685e+26, 6.027e7),URANUS(8.683e+25, 2.556e7),NEPTUNE(1.024e+26, 2.477e7);private final double mass;private final double radius;private final double surfaceGravity;private static final double G = 6.67300e-11;Planet(double mass, double radius) {this.mass = mass;this.radius = radius;surfaceGravity = G * mass / (radius * radius);}public double mass() {return mass;}public double radius() {return radius;}public double surfaceGravity() {return surfaceGravity;}public double surfaceWeight(double mass) {//F=mareturn mass * surfaceGravity;}}

根据某个物体在地球上的重量,显示该物体在所有8颗行星上的重量:

public static void main(String[] args) {double earthWeight = 175;double mass = earthWeight / Planet.EARTH.surfaceGravity();for(Planet p : Planet.values()) {System.out.printf("Weight on %s is %f%n", p, p.surfaceWeight(mass));}
}

如果枚举具有普遍适用性,它应该成为一个顶层类,如果只被用在一个特定的顶层类中,应该成为顶层类的一个成员类。

java.math.RoundingMode枚举表示十进制的舍入模式,用在BigDecimal类。

 

Planet示例展示每个常量关联不同的数据,有时候需要将本质上不同的行为与常量关联起来。

假设有一个枚举类型,表示计算器的四大基本操作:

public enum Operation {PLUS("+") {double apply(double x, double y) {return x + y;}},MINUS("-") {double apply(double x, double y) {return x - y;}},TIMES("*") {double apply(double x, double y) {return x - y;}},DIVIDE("/") {double apply(double x, double y) {return x - y;}};private final String symbol;Operation(String symbol) {this.symbol = symbol;}public String toString() {return symbol;}abstract double apply(double x, double y);
}

某些情况下,覆盖toString方法使打印算术表达式很容易:

public static void main(String[] args) {double x = 2.0;double y = 4.0;for(Operation op : Operation.values())System.out.printf("%f %s %f = %f%n", x, op, y, op.apply(x,y));
}

枚举类型有一个自动产生的valueOf(String)方法,它将常量的名字转变成常量本身。

如果覆盖toString方法,要考虑编写一个fromString方法,将字符串表示法变回相应的枚举:

private static final Map stringToEnum= new HashMap();
static {for(Operation op : values())stringToEnum.put(op.toString(), op);
}
public static Operation fromString(String symbol) {return stringToEnum.get(symbol);
}

 

枚举策略解决多个枚举常量同时共享相同的行为。

加班报酬,weekday和weekend的计算方式不一样:

enum PayrollDay {MONDAY(PayType.WEEKDAY),THESDAY(PayType.WEEKDAY),WEDNESDAY(PayType.WEEKDAY),THURSDAY(PayType.WEEKDAY),FRIDAY(PayType.WEEKDAY),SATURDAY(PayType.WEEKEND),SUNDAY(PayType.WEEKEND);private final PayType p;PayrollDay(PayType p) {this.p = p;}double pay(double hoursWorked, double payRate) {return payType.pay(hoursWorked, payRate);}private enum PayType {WEEKDAY {double overtimePay(double hours, double payRate) {return hours <= HOURS_PER_SHIFT ? 0 :(hours - HOURS_PER_SHIFT) * payRate * 2;}},WEEKEND {double overtimePay(double hours, double payRate) {return hours * payRate / 2;}};private final static int HOURS_PER_SHIFT = 8;abstract double overtimePay(double hours, double Rate);double pay(double hoursWorked, double payRate) {double basePay = hoursWorked * payRate;return basePay + overtimePay(hoursWorked, payRate);}}
}

每当需要一组固定常量的时候,就应该使用枚举。


推荐阅读
  • Java学习笔记之面向对象编程(OOP)
    本文介绍了Java学习笔记中的面向对象编程(OOP)内容,包括OOP的三大特性(封装、继承、多态)和五大原则(单一职责原则、开放封闭原则、里式替换原则、依赖倒置原则)。通过学习OOP,可以提高代码复用性、拓展性和安全性。 ... [详细]
  • Java太阳系小游戏分析和源码详解
    本文介绍了一个基于Java的太阳系小游戏的分析和源码详解。通过对面向对象的知识的学习和实践,作者实现了太阳系各行星绕太阳转的效果。文章详细介绍了游戏的设计思路和源码结构,包括工具类、常量、图片加载、面板等。通过这个小游戏的制作,读者可以巩固和应用所学的知识,如类的继承、方法的重载与重写、多态和封装等。 ... [详细]
  • IjustinheritedsomewebpageswhichusesMooTools.IneverusedMooTools.NowIneedtoaddsomef ... [详细]
  • 先看官方文档TheJavaTutorialshavebeenwrittenforJDK8.Examplesandpracticesdescribedinthispagedontta ... [详细]
  • 本文介绍了闭包的定义和运转机制,重点解释了闭包如何能够接触外部函数的作用域中的变量。通过词法作用域的查找规则,闭包可以访问外部函数的作用域。同时还提到了闭包的作用和影响。 ... [详细]
  • Iamtryingtomakeaclassthatwillreadatextfileofnamesintoanarray,thenreturnthatarra ... [详细]
  • Java容器中的compareto方法排序原理解析
    本文从源码解析Java容器中的compareto方法的排序原理,讲解了在使用数组存储数据时的限制以及存储效率的问题。同时提到了Redis的五大数据结构和list、set等知识点,回忆了作者大学时代的Java学习经历。文章以作者做的思维导图作为目录,展示了整个讲解过程。 ... [详细]
  • JavaSE笔试题-接口、抽象类、多态等问题解答
    本文解答了JavaSE笔试题中关于接口、抽象类、多态等问题。包括Math类的取整数方法、接口是否可继承、抽象类是否可实现接口、抽象类是否可继承具体类、抽象类中是否可以有静态main方法等问题。同时介绍了面向对象的特征,以及Java中实现多态的机制。 ... [详细]
  • 本文讨论了一个关于cuowu类的问题,作者在使用cuowu类时遇到了错误提示和使用AdjustmentListener的问题。文章提供了16个解决方案,并给出了两个可能导致错误的原因。 ... [详细]
  • 自动轮播,反转播放的ViewPagerAdapter的使用方法和效果展示
    本文介绍了如何使用自动轮播、反转播放的ViewPagerAdapter,并展示了其效果。该ViewPagerAdapter支持无限循环、触摸暂停、切换缩放等功能。同时提供了使用GIF.gif的示例和github地址。通过LoopFragmentPagerAdapter类的getActualCount、getActualItem和getActualPagerTitle方法可以实现自定义的循环效果和标题展示。 ... [详细]
  • 本文详细介绍了Java中vector的使用方法和相关知识,包括vector类的功能、构造方法和使用注意事项。通过使用vector类,可以方便地实现动态数组的功能,并且可以随意插入不同类型的对象,进行查找、插入和删除操作。这篇文章对于需要频繁进行查找、插入和删除操作的情况下,使用vector类是一个很好的选择。 ... [详细]
  • 本文讨论了clone的fork与pthread_create创建线程的不同之处。进程是一个指令执行流及其执行环境,其执行环境是一个系统资源的集合。在调用系统调用fork创建一个进程时,子进程只是完全复制父进程的资源,这样得到的子进程独立于父进程,具有良好的并发性。但是二者之间的通讯需要通过专门的通讯机制,另外通过fork创建子进程系统开销很大。因此,在某些情况下,使用clone或pthread_create创建线程可能更加高效。 ... [详细]
  • 本文介绍了Python爬虫技术基础篇面向对象高级编程(中)中的多重继承概念。通过继承,子类可以扩展父类的功能。文章以动物类层次的设计为例,讨论了按照不同分类方式设计类层次的复杂性和多重继承的优势。最后给出了哺乳动物和鸟类的设计示例,以及能跑、能飞、宠物类和非宠物类的增加对类数量的影响。 ... [详细]
  • Java中包装类的设计原因以及操作方法
    本文主要介绍了Java中设计包装类的原因以及操作方法。在Java中,除了对象类型,还有八大基本类型,为了将基本类型转换成对象,Java引入了包装类。文章通过介绍包装类的定义和实现,解答了为什么需要包装类的问题,并提供了简单易用的操作方法。通过本文的学习,读者可以更好地理解和应用Java中的包装类。 ... [详细]
  • 基于dlib的人脸68特征点提取(眨眼张嘴检测)python版本
    文章目录引言开发环境和库流程设计张嘴和闭眼的检测引言(1)利用Dlib官方训练好的模型“shape_predictor_68_face_landmarks.dat”进行68个点标定 ... [详细]
author-avatar
拍友2602939213
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有