Java学习者论坛

 找回密码
 立即注册

QQ登录

只需一步,快速开始

手机号码,快捷登录

恭喜Java学习者论坛(https://www.javaxxz.com)已经为数万Java学习者服务超过8年了!积累会员资料超过10000G+
成为本站VIP会员,下载本站10000G+会员资源,购买链接:点击进入购买VIP会员
JAVA高级面试进阶视频教程Java架构师系统进阶VIP课程

分布式高可用全栈开发微服务教程

Go语言视频零基础入门到精通

Java架构师3期(课件+源码)

Java开发全终端实战租房项目视频教程

SpringBoot2.X入门到高级使用教程

大数据培训第六期全套视频教程

深度学习(CNN RNN GAN)算法原理

Java亿级流量电商系统视频教程

互联网架构师视频教程

年薪50万Spark2.0从入门到精通

年薪50万!人工智能学习路线教程

年薪50万!大数据从入门到精通学习路线年薪50万!机器学习入门到精通视频教程
仿小米商城类app和小程序视频教程深度学习数据分析基础到实战最新黑马javaEE2.1就业课程从 0到JVM实战高手教程 MySQL入门到精通教程
查看: 701|回复: 0

[枚举学习]说说Java中的枚举(二)

[复制链接]
  • TA的每日心情
    开心
    2021-3-12 23:18
  • 签到天数: 2 天

    [LV.1]初来乍到

    发表于 2014-10-29 23:57:08 | 显示全部楼层 |阅读模式
    到目前为止,我们仅仅使用了最简单的语法定义枚举类型,其实枚举类型可以做更多的事情,在Tiger的定义中,枚举是一种新的类型,允许用常量来表示特定的数据片断,它能胜任普通类的大部分功能,如定义自己的构造函数、方法、属性等等。这也是java与C/C++或是Pascal中不同的地方,在那两种语言中枚举类型代表的就是一些int类型的数字,但在Java中枚举更像是一个类。     接下来我们将丰富一下我们的枚举类型。  前面定义了包含五个工作日的枚举类型,但是真正在每个工作日进行操作的动作是在其它类中的printWeekDay方法中进行的。假设我们经过分析发现对工作日的操作应该属于枚举类型WeekDay的职责,那我们就可以把枚举类型改造如下:  
       
         
          
          Java代码
          
          
          public enum WeekDay {                    MONDAY, TUESDAY, WENSDAY, THURSDAY, FRIDAY;                              /**                 * 根据工作日的不同打印不同的信息。                 */                  public void printWeekDay(){                   switch(this){                    case MONDAY: System.out.println(“Today is Monday!”); break;                    case TUESDAY: System.out.println(“Today is Tuesday!”); break;                    case WENSDAY: System.out.println(“Today is Wensday!”); break;                    case THURSDAY: System.out.println(“Today is Thursday!”); break;         case FRIDAY: System.out.println(“Today is Friday!”); break;                         default:                      throw new AssertionError("Unexpected value: " + this);                     }                } }  //测试程序 for(WeekDay weekDay: EnumSet.allOf(WeekDay.class)){           System.out.println("the message is : "+weekDay.printWeekDay());          }
          
         
             现在的枚举类型Operation变得丰满多了,我们在枚举类型WeekDay中增加了一个printWeekDay方法,你也可以用WeekDay.MONDAY.printWeekDay()方法来进行信息的输出了。     枚举类型也允许定义自己的构造函数,这使得枚举常量可以初始化更多的信息。来看看我们在EnumMap与EnumSet一文中提到过的枚举类型DataBaseType,它存放了现在支持的所有数据库类型。但它仅是一个“代号”,由于和数据库相关的信息对于一个应用程序来说是固定不变的,所以把这些数据放置在枚举类型自身中更符合设计的习惯。  
       
         
          
          Java代码
          
          
          public enum DataBaseType{                              MYSQL("com.mysql.jdbc.Driver", "jdbc:mysql://localhost/mydb"),                    ORACLE("oracle.jdbc.driver.OracleDriver",                                      "jdbc:oracle:thin:@localhost:1521:sample"),                    DB2("com.ibm.db2.jdbc.app.DB2Driver",                                      "jdbc:db2://localhost:5000/sample"),                    SQLSERVER("com.microsoft.jdbc.sqlserver.SQLServerDriver",                                      "jdbc:microsoft:sqlserver://localhost:1433;DatabaseName=mydb");                              private String driver;                              private String url;                    //自定义的构造函数,它为驱动、URL赋值                    DataBaseType(String driver,String url){                             this.driver = driver;                             this.url = url;                    }                     /**                 * 获得数据库驱动                 * @return               */                 public String getDriver() {                             return driver;                 }                     /**                 * 获得数据库连接URL                 * @return                 */                    public String getUrl() {                             return url;                    } }  //测试程序 for(DataBaseType dataBaseType: EnumSet.allOf(DataBaseType.class)){               System.out.println("the driver is : "+dataBaseType.getDriver());               System.out.println("the url is : "+dataBaseType.getUrl());          }
          
         
             你注意到例子中的枚举常量是如何声明使用自定义构造函数初始化的吗?仅需要将初始化使用的数据放入在枚举常量名称后面的括号中就可以了。     现在我们设计出了两个内容丰富的枚举类型,对枚举类型的使用也变得自然了许多。你也许觉得枚举类型和类之间差别甚微。可是毕竟枚举类型有着诸多限制,你在实现自己的枚举类型时一定要遵循它们。     1. 枚举类型不能使用extends关键字,但是可以使用implements关键字。这样我们可以把不同枚举类型共有的行为提取到接口中,来规范枚举类型的行为。     2. 枚举类型的自定义构造函数并不能覆盖默认执行的构造函数,它会跟在默认构造函数之后执行。     3. 枚举类型的自定义构造函数必须是私有的。你不需要在构造函数上添加private关键字,编译器会为我们代劳的。     4. 枚举类型中枚举常量的定义必须放在最上面,其后才能是变量和方法的定义。 模板方法
    谈这个话题前我们要看一下改写的printWeekDay方法,在那个例子里WeekDay是丰富一些了,不过使用switch对枚举常量逐个判断以便定制不同的行为,扩展起来要麻烦了一些。假如为WeekDay添加了一个新的枚举常量,如果你忘了同时为它在switch中添加相应的case标示,那么即使有default标示来提示错误,也只能在运行后才能发现。     怎么做能更好一点?我们前面已经认识到枚举就是一个特殊的类,它可以有方法和属性,同时每个声明的枚举项都是这个枚举类型的一个实例。那么我们能不能使用“模板方法模式”来改造一下这个枚举类呢?当然可以!我们把那个例子重构一下,变成下面这个样子:  
       
         
          
          Java代码
          
          
          public enum WeekDay {                    MONDAY{                             @Override                             public void printWeekDay() {                                      System.out.println(“Today is Monday!”);                             }                    },                    TUESDAY{                             @Override                             public void printWeekDay() {                                      System.out.println(“Today is Tuesday!”);                             }                    },                    WENSDAY{                             @Override                             public void printWeekDay() {                                      System.out.println(“Today is Wensday!”);                             }                    },                    THURSDAY{                             @Override                             public void printWeekDay() {                                    System.out.println(“Today is Thursday!”);                             }                    },                    FRIDAY{                             @Override                             public void printWeekDay() {                                      System.out.println(“Today is Friday!”);                             }                    };                              /**                 * 根据工作日的不同打印不同的信息                 */                    public abstract void printWeekDay();  }
          
         
             首先,我们把方法printWeekDay改为抽象方法,然后我们在每一个枚举常量中实现了在枚举类型里定义的这个抽象方法。这样,每为枚举类型添加一个新的枚举常量,都必须实现枚举类型中定义的抽象方法,不然编译器提示出错。之所以可以这么做的原因是,虚拟机将枚举类型中声明的每一个枚举常量,创建成为一个单独的枚举类型的子类。     这样,再配合使用Tiger里的静态导入,调用者的代码就可以这样写了:  
       
         
          
          Java代码
          
          
          MONDAY.printWeekDay(); TUESDAY.printWeekDay(); //or better... getWeekDay().printWeekDay();
          
         
             这些代码显然要比常见的if(weekDay == WeekDay.MONDAY){...} else if(weekDay == WeekDay.TUESDAY) else {...}形式强多了,它们易读、容易扩展和维护。 反向查找
    前面说到枚举也可以自定义构造函数,可以用属性来关联更多的数据。那如果我们有这样的一种需要该怎么办呢?――我们需要根据关联的数据来得到相应的枚举项,例如下面的这种情况:  
       
         
          
          Java代码
          
          
          public final enum Status {      WAITING(0),      READY(1),      SKIPPED(-1),      COMPLETED(5);       private int code;       private Status(int code) {           this.code = code;      }       public int getCode() { return code; } }
          
         
             这里每种Status对应了一个code,WAITING对应了0,而COMPLETED对应了5。如果想通过0得到WAITING这个枚举项要怎么做?     做法也很简单,使用一个静态的java.util.Map来把code和枚举项关联起来就可以了,就像这样:  
       
         
          
          Java代码
          
          
          public final enum Status {      WAITING(0),      READY(1),      SKIPPED(-1),      COMPLETED(5);       private static final Map<Integer,Status> lookup           = new HashMap<Integer,Status>();       static {           for(Status s : EnumSet.allOf(Status.class)){                lookup.put(s.getCode(), s);           }      }       public static Status get(int code) {           return lookup.get(code);      }       private int code;       private Status(int code) {           this.code = code;      }       public int getCode() { return code; } }
          
         
             静态方法get(int)提供了需求中的反向查找能力,而静态块里使用EnumSet来把起映射做用的Map组装起来,Over! 总结:使用枚举,但不要滥用!     学习任何新版语言的一个危险就是疯狂使用新的语法结构。如果这样做,那么您的代码就会突然之间有 80% 是泛型、标注和枚举。所以,应当只在适合使用枚举的地方才使用它。那么,枚举在什么地方适用呢?一条普遍规则是,任何使用常量的地方,例如目前用 switch 代码切换常量的地方。如果只有单独一个值(例如,鞋的最大尺寸,或者笼子中能装猴子的最大数目),则还是把这个任务留给常量吧。但是,如果定义了一组值,而这些值中的任何一个都可以用于特定的数据类型,那么将枚举用在这个地方最适合不过。 相关文章:《说说java中的枚举(一)
    回复

    使用道具 举报

    您需要登录后才可以回帖 登录 | 立即注册

    本版积分规则

    QQ|手机版|Java学习者论坛 ( 声明:本站资料整理自互联网,用于Java学习者交流学习使用,对资料版权不负任何法律责任,若有侵权请及时联系客服屏蔽删除 )

    GMT+8, 2024-5-18 23:47 , Processed in 0.401167 second(s), 48 queries .

    Powered by Discuz! X3.4

    © 2001-2017 Comsenz Inc.

    快速回复 返回顶部 返回列表