枚举作为一个常规的语言概念,一直到Java5才诞生不得不说有点奇怪,以至于到现在为止很多程序员仍然更喜欢用static final的形式去命名常量而不使用,一般情况下,Java程序员用这种方式去实现枚举:

class EnumByClass{public static final int RED=0;public static final int GREEN=1;public static final int BLUE=2;
}

这种方式实现的枚举也叫int枚举模式,尽管很常用,但是由int实现的枚举很难保证安全性,即当调用不在枚举范围内的数值时,需要额外的维护。另外 ,也不利于查看log和测试。

此时,我们需要开始使用Java的枚举类型,例如上面的int枚举模式类如果用enum实现,那么代码如下:

enum Color{RED,GREEN,BLUE;
}

上述是将枚举作为常量集合的简单用法,实际上,枚举更多的还是用于switch,也是在这时才能发现枚举相对于int枚举模式的好处,这里面举一个用enum实现switch的例子:

enum Color{RED,GREEN,BLUE;
}
public class Hello {public static void main(String[] args){Color color=Color.RED;int counter=10;while (counter-->0){switch (color){case RED:System.out.println("Red");color=Color.BLUE;break;case BLUE:System.out.println("Blue");color=Color.GREEN;break;case GREEN:System.out.println("Green");color=Color.RED;break;}}}
}

如果我们用int枚举模式的话,诚然可以用一些类似++,——的语法糖,但是也要更多的考虑到安全性的问题。

如果仅此而已,那么枚举也没什么单独拿出来写博客的价值。

我个人对enum感兴趣主要是因为之前在介绍Singleton时有一个非常经验的枚举实现的单例,代码如下:

enum SingletonDemo{INSTANCE;public void otherMethods(){System.out.println("Something");}
}

简简单单的一点代码就实现了一个线程安全的单例,与其说是写法鬼斧神工,不如说是恰如其分地应用了enum的性质。

在用enum实现Singleton时我曾介绍过三个特性,自由序列化,线程安全,保证单例。这里我们就要探讨一下why的问题。

首先,我们都知道enum是由class实现的,换言之,enum可以实现很多class的内容,包括可以有member和member function,这也是我们可以用enum作为一个类来实现单例的基础。另外,由于enum是通过继承了Enum类实现的,enum结构不能够作为子类继承其他类,但是可以用来实现接口。此外,enum类也不能够被继承,在反编译中,我们会发现该类是final的。

其次,enum有且仅有private的构造器,防止外部的额外构造,这恰好和单例模式吻合,也为保证单例性做了一个铺垫。这里展开说下这个private构造器,如果我们不去手写构造器,则会有一个默认的空参构造器,我们也可以通过给枚举变量参量来实现类的初始化。这里举一个例子。

enum Color{RED(1),GREEN(2),BLUE(3);private int code;Color(int code){this.code=code;}public int getCode(){return code;}
}

需要注意的是,private修饰符对于构造器是可以省略的,但这不代表构造器的权限是默认权限。

目前我们对enum的结构和特性有了初步的了解,接下来探究一下原理层次的特性。

想要了解enum是如何工作的,就要对其进行反编译。

反编译后就会发现,使用枚举其实和使用静态类内部加载方法原理类似。枚举会被编译成如下形式:

public final class T extends Enum{

...

}

其中,Enum是Java提供给编译器的一个用于继承的类。枚举量的实现其实是public static final T 类型的未初始化变量,之后,会在静态代码中对枚举量进行初始化。所以,如果用枚举去实现一个单例,这样的加载时间其实有点类似于饿汉模式,并没有起到lazy-loading的作用。

对于序列化和反序列化,因为每一个枚举类型和枚举变量在JVM中都是唯一的,即Java在序列化和反序列化枚举时做了特殊的规定,枚举的writeObject、readObject、readObjectNoData、writeReplace和readResolve等方法是被编译器禁用的,因此也不存在实现序列化接口后调用readObject会破坏单例的问题。

对于线程安全方面,类似于普通的饿汉模式,通过在第一次调用时的静态初始化创建的对象是线程安全的。

因此,选择枚举作为Singleton的实现方式,相对于其他方式尤其是类似的饿汉模式主要有以下优点:

1. 代码简单

2. 自由序列化

至于lazy-loading,考虑到一般情况不存在调用单例类又不需要实例化单例的情况,所以即便不能做到很好的lazy-loading,也并不是大问题。换言之,除了枚举这种方案,饿汉模式也在单例设计中广泛的被应用。例如,Hibernate默认的单例,获取sessionFactory用的HibernateUtil类建立方式如下:

public class HibernateUtil {private static final SessionFactory ourSessionFactory;static {try {Configuration configuration = new Configuration();configuration.configure();ourSessionFactory = configuration.buildSessionFactory();} catch (Throwable ex) {throw new ExceptionInInitializerError(ex);}}public static Session getSession() throws HibernateException {return ourSessionFactory.openSession();}
}

这是一个典型的饿汉模式,考虑到这个单例只有一个方法即getSession,显然这种模式本身就是最优的且简洁的。这里面由于SessionFactory的创建并不是用系统默认的方式,如果想要用enum去实现反而麻烦且无必要。不过至少说明这样做也许需要一个解决自由序列化的问题。

转载于:https://www.cnblogs.com/cielosun/p/6596475.html

Java枚举enum以及应用:枚举实现单例模式相关推荐

  1. java获取枚举的值_JAVA枚举Enum,通过枚举值获取枚举类型

    枚举类: import java.util.Optional; public enum PurchaseDemandEnum { YJJSL(1,"研究技术类"), XTGCL(2 ...

  2. java switch enum对象_Java枚举类(enum)5种常见用法和3种内部方法,详细附代码

    文章目录 Java枚举类(enum)重点用法和内部方法,附代码 一.Java 枚举类(enum) 详解5种常见的用法 1.常量 2.支持switch 3.向枚举中添加新方法 4.覆盖枚举的方法 5.实 ...

  3. java 枚举_Java中的枚举类型(Enum)详解

    文章前记 程序员工作久了便可能整日忙碌于"增删改查"中,迷失方向,毫无进步. 该公众号致力于分享软件开发相关的原创干货,助你完成从程序员到架构师的进阶之路! 努力!做一个NB的Co ...

  4. java枚举比较大小写_Java 枚举(enum)的学习

    Java 枚举(enum)的学习 枚举的定义 在定义枚举类型时我们使用的关键字是enum,与class关键字类似,只不过前者是定义枚举类型,后者是定义类类型.枚举类型Day中分别定义了从周一到周日的值 ...

  5. 枚举类型enum用法_Java枚举深度解读,看这篇就够了

    作者 | 涛GuoGuo的跟屁虫丶博Ke 来源 | urlify.cn/aaamQf 66套java从入门到精通实战课程分享 Java枚举 1.枚举类概念的理解与定义 一个类的对象是有限个,确定的,我 ...

  6. Java SE 059 类型安全的枚举

    (1)一个人只要自己不放弃自己,整个世界也不会放弃你. (2)天生我才必有大用 (3)不能忍受学习之苦就一定要忍受生活之苦,这是多么痛苦而深刻的领悟 (4)做难事必有所得 (5)精神乃真正的刀锋 (6 ...

  7. c++ enum 给定类型_C++11作用域内枚举enum

    在C++11之前的枚举(enum),是没有办法两个枚举(enum)内有相同枚举名的.如果还不知道C++中枚举(enum)是什么,可以看这篇:枚举enum 如:苹果和桔子都有大,中,小.写个代码来说明下 ...

  8. Java--枚举类型(枚举类型介绍 定义枚举类型 枚举类型的使用 枚举类型的注意事项 遍历枚举项)

    01: Java–枚举类型(枚举类型介绍 & 定义枚举类型 & 枚举类型的使用 & 枚举类型的注意事项 & 遍历枚举项) 02: Java–枚举类型(枚举类型实现接口 ...

  9. Java设计模式——为什么要用枚举实现单例模式(避免反射、序列化问题)

    1.序言   相信如果能看到我这篇博客的小伙伴,肯定都看过Joshua Bloch大神说过的这句话:"单元素的枚举类型已经成为实现Singleton的最佳方法".其实,第一次读到这 ...

最新文章

  1. 了解EOS看这一篇就够了一、团队二、技术三、项目进度四、争议和风险五、展望
  2. XML,Object,Json分析转换Xstream采用
  3. 记一次 Spring Boot 项目启动卡住问题排查记录
  4. 详解Scala函数也是对象的特性
  5. 什么是ABAP的STATE_READ_ACCESS
  6. Python 模板语言
  7. 3-40HDFS读数据流程
  8. 2022春节行为经济学
  9. 特斯拉得克萨斯超级工厂正式开业 计划明年开始生产电动皮卡
  10. atitit.为什么技术的选择方法java超过.net有前途
  11. 电磁场中场点和源点及▽(R)▽(1/R)▽.▽(1/R)
  12. 超级好用的TXT分本分割工具
  13. 广域网宽带接入技术一
  14. 微信公众号 Markdown 编辑器
  15. linux的命令解释器-----shell
  16. 10个流行常用的Django第三方包-大江狗推荐
  17. 日本亚马逊海淘经验-2015
  18. android 复制u盘文件到手机本地_如何将手机里的文件 、照片传到手机U盘里去?...
  19. Python编程之外星人入侵(一)
  20. 水果小买卖c语言,C语言排序(1)___水果销售

热门文章

  1. 阿里巴巴矢量图标库iconfont使用教程
  2. jenkins清除、修改admin主账号的密码
  3. Python Scrapy创建spider及结果导出命令
  4. Java客户端操作HBase:插入数据(逐条插入与批量插入)代码示例
  5. JVM内存压缩开启/不开启各占几个字节
  6. 通过反射给属性赋值代码示例
  7. 使用Java客户端操作elasticsearch--设置mappings、添加文档、查询数据
  8. class没有发布到tomcat_面试官扎心一问:Tomcat 在 SpringBoot 中是如何启动的?
  9. Coding:就地合并两个排序数组
  10. Comparable接口和Comparator接口的比较