`
simgsg
  • 浏览: 96047 次
  • 性别: Icon_minigender_1
  • 来自: 北京
文章分类
社区版块
存档分类
最新评论

Java中的枚举(二)

 
阅读更多

到目前为止,我们仅仅使用了最简单的语法定义枚举类型,其实枚举类型可以做更多的事情,在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枚举实例代码

    Java枚举(enum)是Java语言中的一种特殊数据类型,用于定义一组有限的常量,这些常量在程序中作为固定的值使用。枚举在Java中被引入,目的是为了更好地管理和使用常量,提高代码的可读性和安全性。在本实例代码中,...

    java中枚举的使用

    在枚举中,我们可以定义方法,这些方法可以是抽象的,也可以包含具体实现。例如,我们可以定义一个返回枚举常量名称的方法: ```java public enum Color { RED, GREEN, BLUE; public String getName() { return...

    java enum 枚举 学习资料

    枚举类中可以显式的指明调用哪个构建器,如 MEMBER 和 MEMBER() 这两种元素列表声明是等价的,都是调用默认的构建器,而 MEMBER("普通会员") 则是显式的指明程序调用第二个构建器。 3. 枚举类中的方法 枚举类中...

    说说Java中的枚举 转 可以了,够了 包括EnumSet(Map)

    这篇博客将深入探讨Java枚举的特性和使用方法,包括`EnumSet`和`EnumMap`这两个与枚举相关的数据结构。 首先,枚举定义的基本语法是`public enum EnumName {constant1, constant2, ...}`。每个枚举常量都是`...

    java 通过反射获取枚举类,及枚举类的值,枚举类枚举实例名

    枚举(Enumeration)是Java中的一个特殊类类型,用于定义一组常量。本项目"test-enum-demo-master"显然是一个用于演示如何通过反射来操作枚举类的示例。 首先,让我们理解枚举类的基本概念。枚举类在Java中用于定义...

    java枚举结果类、根据状态值获取枚举值

    java枚举结果类、根据状态值获取枚举值 Controller: /** 模块类型枚举 */ model.addAttribute("mType", ModuleTypeEnum.ModuleTypeShow()); ftl: value="${mType.key}:${mType.value}” &lt;/#list&gt;

    Java面试枚举从使用到原理

    本篇文章将深入探讨Java枚举的使用及其背后的原理。 一、枚举的定义与使用 1. 基本用法: 在Java中,枚举可以通过`enum`关键字来创建。例如,我们可以定义一个表示一周七天的枚举类型: ```java public enum ...

    Java枚举类型Enum的用法

    在枚举内部,可以通过`Enum&lt;E extends Enum&lt;E&gt;&gt;`的泛型方法`getDeclaringClass()`获取枚举常量所属的枚举类,以及`name()`和`ordinal()`方法获取常量的名称和在枚举中的位置。 总结来说,Java枚举类型提供了一种...

    简单总结java枚举类型

    枚举在Java中被引入为一个完整的类型,不同于C++中的枚举,这使得Java枚举更加强大且易于使用。以下是关于Java枚举类型的详细解释和相关知识点: 1. 定义枚举: 在Java中,枚举通过关键字`enum`来定义。例如,创建...

    java枚举ppt和详细代码

    枚举中的每个实例都是唯一的,且在程序启动时自动初始化,无需担心多线程环境下的安全问题。例如,下面的Singleton枚举类: ```java enum Singleton { INSTANCE; public void doSomething() { // ... } } ...

    java枚举类型说明

    #### 二、Java枚举的基本概念 Java中的枚举是一种特殊的类,用于定义一组固定的常量值。相比于传统的`public static final`变量,枚举提供了更多的灵活性和安全性。下面是一些关于Java枚举的基础知识点: - **定义...

    java中enum枚举的详细用法

    Java中的枚举(enum)类型是在JDK 1.5版本引入的一个强大的特性,它用于定义一组相关的常量。在C/C++等语言中,枚举通常用来表示一组具有固定值的常量集合,但在Java中,枚举不仅限于此,它提供了更多的功能和灵活性...

    Java中的“枚举类型

    - **枚举元素的实例性质**:枚举中的每个元素实际上是一个对象实例,这意味着可以为这些元素添加额外的属性和行为。例如,为不同的季节分配特定的颜色或温度范围。 - **枚举类的可扩展性**:除了定义枚举元素外,...

    java枚举状态机

    在Java枚举中,每个状态可以是一个枚举常量,而状态间的转换可以通过定义方法来实现。 例如,假设我们有一个简单的订单处理系统,有"新建"、"处理中"和"完成"三个状态,可以这样定义枚举: ```java public enum ...

    JAVA的枚举实例以及应用

    JAVA的枚举实例以及应用

    JAVA高级编程中Enum枚举

    5. **枚举常量的自然顺序**:枚举常量按照声明的顺序进行排序,可以用`ordinal()`方法获取其在枚举中的位置。 在实际编程中,枚举可以用于实现模式匹配、单例模式等多种设计模式。例如,可以定义一个状态枚举来表示...

    在Java中使用枚举

    - Java中的枚举定义非常简洁,可以直接在枚举中定义值: ```java public enum Day { SUNDAY, MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY; } ``` - 与C++中的枚举不同,Java枚举默认是单例的,...

    理解java枚举类型

    例如,我们可以在枚举中定义一个返回枚举名称的方法: ```java public enum Color { RED, GREEN, BLUE; public String getName() { return name(); } } ``` 然后,`Color.RED.getName()`将返回"RED"。 四、枚举...

    java枚举类用法

    通过上述介绍,我们了解到Java枚举类的多种用法,包括声明、初始化、方法定义、构造器、转换为集合、遍历、比较、在switch语句中的应用以及序列化等。枚举类不仅提高了代码的可读性和安全性,还简化了常量管理,使得...

    java中枚举的详细使用介绍

    - `compareTo`:比较枚举实例的顺序,基于它们在枚举中的定义顺序。 - `name`:返回枚举实例的名称,通常与定义时的标识符相同。 - `ordinal`:返回枚举值在枚举中的索引,从0开始。 - `toString`:返回枚举实例的...

Global site tag (gtag.js) - Google Analytics