• JAVA中的枚举(enum)
  • 超级玛丽 发表于 2014/12/25 13:04:00 | 分类标签: JAVA 枚举 enum
  •  

    Java的枚举是一个“class”

    Java的早期版本时没有enum的,大家都用interface里加常量的方式实现,Java 1.5版本之后添加了对enum的支持。

    Java认为类C的枚举不是类型安全的(type safe),所以Java中没有枚举,Java的枚举就是类(Enum Class),只是用了一个enum代替class而已(虽然.NET里在MSIL层面枚举最终也是一种“class”)。因为Java的枚举是类,所以就带来一些与C#中的枚举有趣的不同点,比如可以添加方法,可以添加属性。请看下面的Java代码:

       1: public enum Role{
       2:     Admin("管理员"),
       3:     Owner("所有者"),
       4:     Creator("创建者");
       5:  
       6:     private String displayName;
       7:  
       8:     Role(String displayName){
       9:         this.displayName = displayName;
      10:     }
      11:  
      12:     public String getDisplayName(){
      13:         return this.displayName;
      14:     }
      15: }

    Java的枚举居然可以这么写!枚举里可以有方法。这里的Admin,Owner,Creator实际上是Role类的常量,调用Role(String)构造器,但是Java不允许你将enum的构造器设为public,由Java自己内部调用。

    有人可能会问这样有什么用处呢?比如上面这段代码,建一个枚举表示系统中的所有角色,为了用户友好性,数据库里我们保存角色名字,但是在系统界面上我们要显示一个更具描述性的名字,而且假如我们的系统需要多语言化,那么在不同的语言平台上的界面上我们的系统应该显示不同的描述性短语(注意:.NET中的枚举是不能国际化的),比如下面的界面:

    image

    image

    那我们就可以这样做:

       1: public enum Role{
       2:     Admin("role-admin"),
       3:     Owner("role-owner"),
       4:     Creator("role-creator");
       5:  
       6:     private String displayName;
       7:  
       8:     Role(String displayName){
       9:         this.displayName = displayName;
      10:     }
      11:  
      12:     public String getDisplayName(){
      13:         return Resource.get(this.displayName);
      14:     }
      15: }

    我们这里getDisplayName的时候调用一个国际化的API,通过枚举构造器里传入的参数作为key获取国际化的表示。

    Java的enum是类型安全、版本安全的

    这样一说好像C#的enum不是类型安全的一样,哼!嗯,某种角度上来说C#(本文以C#指代整个.NET平台)的枚举真的不是类型安全的。比如下面的代码:

       1: using System;
       2: public enum Role:short
       3: {
       4:     Admin,Owner,Creator
       5: }
       6:  
       7: public class Program
       8: {
       9:     public static void Main(String[] args)
      10:     {
      11:         byte i = (byte)Role.Owner;
      12:     }
      13: }

    即使我们给C#的enum指定了underlying type,但是我们还是可以将其任意的与基本类型进行转换。而且这种转换是静悄悄地进行的,编译器和运行时都不会提醒我们。

    C#的enum完全是一个常量,所以跟C#的const一样还会带来版本的问题。比如A程序集定义了一个枚举Role,B程序集引用A程序集,使用Role,实际上在运行时B程序集不再需要A程序集了(大家知道什么原因吧)。这样如果A程序集修改了Role,比如修改了枚举常量的顺序:从Admin,Owner,Creator变为Admin,Creator,Owner。而B程序集没有重新编译,这个时候就会出现问题。

    C#中实现Enum class

    实际上Enum Class是一种模式,只是java的enum将这种模式放到了语言中,我们在C#里一样可以实现:

       1: public sealed Class Role
       2: {
       3:     public static readonly Role Admin = new Role("role-admin");
       4:     public static readonly Role Owner = new Role("role-owner");
       5:     public static readonly Role Creator = new Creator("role-creator");
       6:  
       7:     private String displayName;
       8:  
       9:     private Role(String displayName)
      10:     {
      11:         this.displayName = displayName;
      12:     }
      13:     
      14:     public String DisplayName
      15:     {
      16:         get
      17:         {
      18:             Resource.Get(this.displayName);
      19:         }
      20:     }
      21: }

    只是实现起来比java的默认实现繁琐一点而已,毕竟那是人家语言的first class。

    位标记

    如果在C#的enum上添加[Flags]的特性话,这个enum就不再是enum了,就变成了位标记。位标记这东西在实现某些功能时确实非常滴方便,比如一个文件的属性:只读,只写,可读写,比如权限控制系统等等。Java的枚举就不能添加这么一个annotation了,不过Java有个EnumSet,我们借助这个API实现位标记同样的功能。

    后记

    Java的enum与C#的enum各有特色,Java的enum更灵活一些,C#的enum更轻型一些,但是使用时请注意C#的enum的一些问题。

  • 请您注意

    ·自觉遵守:爱国、守法、自律、真实、文明的原则

    ·尊重网上道德,遵守《全国人大常委会关于维护互联网安全的决定》及中华人民共和国其他各项有关法律法规

    ·严禁发表危害国家安全,破坏民族团结、国家宗教政策和社会稳定,含侮辱、诽谤、教唆、淫秽等内容的作品

    ·承担一切因您的行为而直接或间接导致的民事或刑事法律责任

    ·您在编程中国社区新闻评论发表的作品,本网站有权在网站内保留、转载、引用或者删除

    ·参与本评论即表明您已经阅读并接受上述条款

  • 感谢本文作者
  • 作者头像
  • 昵称:超级玛丽
  • 加入时间:2013/6/13 0:00:00
  • TA的签名
  • 这家伙很懒,虾米都没写
  • +进入TA的空间
  • 以下内容也很赞哦
分享按钮