单元素枚举类实现单例模式

本文转载自:点击打开链接

Inspired by Effective Java.

Singleton模式是在编程实践中应用最广泛的几种设计模式之一。以前知道的,实现单例的方法有两种(下面的A、B)。刚刚在读《Effective Java的时候》学到一种新的更好的方法(E):单元素的枚举类型。同时通过网上资料也知道了其他两种方法(C、D)。最后一种在Java中从1.5版本开始支持,其他语言在验证后说明。

A.饿汉式(类加载的时候就创建实例)。
代码如下:

public class MaYun {
public static final Mayun instance = new Mayun(); //静态的final的MaYun
private MaYun() {
//MaYun诞生要做的事情
}
public void splitAlipay() {
System.out.println(“Alipay是我的啦!看你丫Yahoo绿眉绿眼的望着。。。”);
}
}
Call:MaYun.instance.splitAlipay();

Feature:可以通过反射机制攻击;线程安全[多个类加载器除外]。

A+.饿汉变种[推荐]

public class MaYun {
private static Mayun instance = new Mayun();
private static getInstance() {
return instance;
}
private MaYun() {
//MaYun诞生要做的事情
}
public void splitAlipay() {
System.out.println(“Alipay是我的啦!看你丫Yahoo绿眉绿眼的望着。。。”);
}
}

A++.饿汉变种(类初始化的时候实例化instance):

public class MaYun {
private MaYun instance = null;
static {
instance = new MaYun();
}
private MaYun() {
//MaYun诞生要做的事情
}
public static MaYun getInstance() {
return this.instance;
}
public void splitAlipay() {
System.out.println(“Alipay是我的啦!看你丫Yahoo绿眉绿眼的望着。。。”);
}
}

B.懒汉式。
代码如下:

public class MaYun {
private static MaYun instance = null;
private MaYun() {
//MaYun诞生要做的事情
}
public static MaYun getInstance() {
if (instance == null) {
instance = new MaYun();
}
return instance;
}
public void splitAlipay() {
System.out.println(“Alipay是我的啦!看你丫Yahoo绿眉绿眼的望着。。。”);
}
}
Call:MaYun.getInstance().splitAlipay();

Feature:延时加载;线程不安全,多线程下不能正常工作;需要额外的工作(Serializable、transient、readResolve())来实现序列化。

B+.懒汉式变种。

public class MaYun {
private static MaYun instance = null;
private MaYun() {
//MaYun诞生要做的事情
}
public static synchronized MaYun getInstance() {
if (instance == null) {
instance = new MaYun();
}
return instance;
}
public void splitAlipay() {
System.out.println(“Alipay是我的啦!看你丫Yahoo绿眉绿眼的望着。。。”);
}
}

Feature:线程安全;效率比较低,因为需要线程同步的时候比较少。

C.静态内部类[推荐]。
代码如下:

public class MaYun {
private static class SigletonHolder {
private static final instance = new MaYun();
}
public static final getInstance() {
return SigletonHolder.instance;
}
private MaYun() {
//MaYun诞生要做的事情
}
public void splitAlipay() {
System.out.println(“Alipay是我的啦!看你丫Yahoo绿眉绿眼的望着。。。”);
}
Call:MaYun.getInstance().splitAlipay();

Feature:线程安全;延迟加载。

D.双重校验锁[不推荐]。
代码如下:

public class MaYun {
private volatile static MaYun instance;
private MaYun (){}
public static MaYun getInstance() {
if (instance == null) {
synchronized (MaYun.class) {
if (instance == null) {
instance = new MaYun();
}
}
}
return instance;
}
}

Feature:jdk1.5之后才能正常达到单例效果。

E.编写一个包含单个元素的枚举类型[极推荐]。
代码如下:

public enum MaYun {
himself; //定义一个枚举的元素,就代表MaYun的一个实例
private String anotherField;
MaYun() {
//MaYun诞生要做的事情
//这个方法也可以去掉。将构造时候需要做的事情放在instance赋值的时候:
/** himself = MaYun() {
* //MaYun诞生要做的事情
* }
**/
}
public void splitAlipay() {
System.out.println(“Alipay是我的啦!看你丫Yahoo绿眉绿眼的望着。。。”);
}
}
Call:MaYun.himself.splitAlipay();

Feature:从Java1.5开始支持;无偿提供序列化机制,绝对防止多次实例化,即使在面对复杂的序列化或者反射攻击的时候。

总之,五类:懒汉,恶汉,双重校验锁,静态内部类,枚举。
恶汉:因为加载类的时候就创建实例,所以线程安全(多个ClassLoader存在时例外)。缺点是不能延时加载。
懒汉:需要加锁才能实现多线程同步,但是效率会降低。优点是延时加载。
双重校验锁:麻烦,在当前Java内存模型中不一定都管用,某些平台和编译器甚至是错误的,因为instance = new MaYun()这种代码在不同编译器上的行为和实现方式不可预知。
静态内部类:延迟加载,减少内存开销。因为用到的时候才加载,避免了静态field在单例类加载时即进入到堆内存的permanent代而永远得不到回收的缺点(大多数垃圾回收算法是这样)。
枚举:很好,不仅能避免多线程同步问题,而且还能防止反序列化重新创建新的对象。但是失去了类的一些特性,没有延迟加载,用的人也太少了~~

以后多推广推广单元素枚举这种更好的单例实现方式。在项目中的代码开始修改实施

下面小demo示范一下,这是只有一个元素的枚举类,枚举类里面也可以写方法。

[java] view plaincopy
在CODE上查看代码片派生到我的代码片
  1. package go.derek;  
  2.   
  3. public enum EnumSingleton {  
  4.     instance;  
  5.     public void doSomething(){  
  6.         System.out.println("do something");  
  7.     }  
  8. }  

测试类如下:

[java] view plaincopy
在CODE上查看代码片派生到我的代码片
  1. package go.derek;  
  2.   
  3. import java.lang.reflect.Constructor;  
  4. import java.lang.reflect.InvocationTargetException;  
  5.   
  6.   
  7. public class Test {  
  8.     public static void main(String[] args) throws InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {  
  9.          Constructor<?>[] array= EnumSingleton.class.getDeclaredConstructors();  
  10.           for (Constructor<?> c : array){  
  11.               c.setAccessible(true);  
  12.               //此处会抛出异常  
  13.               c.newInstance();  
  14.           }  
  15.            
  16.     }  
  17. }  
运行结果如下:

Exception in thread "main" java.lang.IllegalArgumentException: Cannot reflectively create enum objects
at java.lang.reflect.Constructor.newInstance(Constructor.java:521)
at go.derek.Test.main(Test.java:13)

可见,不能通过反射来创建枚举对象,所以这种单例模式可以抵御恶意客户端通过反射的攻击。此外,枚举类的单例模式也不必担心反序列化的时候多次创建实例。


本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/419438.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

搭建spring MVC项目

首先&#xff0c;是要放入spring mvc所需要的包&#xff1a; 如果不用json功能就不需要json和gson包,还有数据库驱动包&#xff0c;我这里是用的postgresql数据库&#xff0c;其他数据库需替换掉这个包 然后就是配置文件&#xff1a; 先是web.xml中需要加入以下内容&#xff…

Serena Dimensions 介绍

Serena Dimensions是配置管理工具&#xff0c;基于进程的软件更改和配置管理解决方案。 官方网址&#xff1a;http://www.serena.com/index.php/en/products/application-development/dimensions-cm/overview/ eclipse与Dimensions的集成 转载于:https://www.cnblogs.com/seabi…

使用jquery图表插件jqplot之折线图

首先一个简单的折线图&#xff1a; 直接上代码&#xff1a; <html> <head> <meta http-equiv"Content-Type" content"text/html; charsetutf-8"> <script type"text/javascript" src"js/jquery.min.js"></…

计算机网络协议包头赏析-TCP

转载自博客地址为http://roclinux.cn。 仍然先把TCP报文段的格式放在这里&#xff0c;然后我们看图说话&#xff1a; TCP报文段也分为首部和数据两部分&#xff0c;首部默认情况下一般是20字节长度&#xff0c;但在一些需求情况下&#xff0c;会使用“可选字段”&#xff0c;这…

Android使用webview控件加载本地html,通过Js与后台Java实现数据的传递

1.在布局文件中加WebView控件&#xff0c;在java中获取WebView对象。 2.加载本地html文件。 webView.loadUrl("file:///android_asset/android.html"); 3.开启js功能。 webView.getSettings().setJavaScriptEnabled(true); 4.添加一个js交互接口&#xff…

TreeMap的讲解

本文转载自&#xff1a;http://blog.csdn.net/chenssy/article/details/26668941点击打开链接 原文出自&#xff1a;http://cmsblogs.com/?p1013。尊重作者的成果&#xff0c;转载请注明出处&#xff01; 个人站点&#xff1a;http://cmsblogs.com ----------------------…

spring使用注解@Scheduled执行定时任务

最近做的项目中遇到了用spring中Schedule注解执行定时任务的功能&#xff0c;这里简单记录一下。 首先在applicationContext.xml中进行配置&#xff1a; xmlns 加下面的内容 xsi:schemaLocation加下面的内容 最后我们的task任务扫描注解 需要注意的几点&#xff1a; 1、spring的…

DIY Ruby CPU 分析 Part II

【编者按】作者 Emil Soman&#xff0c;Rubyist&#xff0c;除此之外竟然同时也是艺术家&#xff0c;吉他手&#xff0c;Garden City RubyConf 组织者。本文是 DIY Ruby CPU Profiling 的第二部分。本文系 OneAPM 工程师编译整理。 在第一部分中我们学习了 CPU 分析的含义和进行…

荐 Intellij IDEA创建Maven Web项目(带有webapp文件夹目录的项目)

转载自&#xff1a;点击打开链接 在创建项目中&#xff0c;IDEA提供了很多项目模板&#xff0c;比如Spring MVC模板&#xff0c;可以直接创建一个基于Maven的Spring MVC的demo&#xff0c;各种配置都已经设定好了&#xff0c;直接编译部署就可以使用。 最开始自己创建maven we…

iOS设计模式 - 迭代器

iOS设计模式 - 迭代器 原理图 说明 提供一种方法顺序访问一个聚合对象中的各种元素&#xff0c;而又不暴露该对象的内部表示。 源码 https://github.com/YouXianMing/iOS-Design-Patterns // // Node.h // IteratorPattern // // Created by YouXianMing on 15/10/26. // …

Android M 新的运行时权限开发者需要知道的一切

android M 的名字官方刚发布不久&#xff0c;最终正式版即将来临&#xff01; android在不断发展&#xff0c;最近的更新 M 非常不同&#xff0c;一些主要的变化例如运行时权限将有颠覆性影响。惊讶的是android社区鲜有谈论这事儿&#xff0c;尽管这事很重要或许在不远的将来会…

SpringMVC关于json、xml自动转换的原理研究[附带源码分析]

目录 前言现象源码分析实例讲解关于配置总结参考资料 前言 SpringMVC是目前主流的Web MVC框架之一。 如果有同学对它不熟悉&#xff0c;那么请参考它的入门blog&#xff1a;http://www.cnblogs.com/fangjian0423/p/springMVC-introduction.html 现象 本文使用的demo基于maven…

Android为网络请求自定义加载动画

android自带的加载动画都不怎么好看&#xff0c;在这里介绍一种自定义加载动画的方法 原始图片&#xff1a; 编写动画progressbar.xml, <?xml version"1.0" encoding"utf-8"?> <animated-rotate android:drawable"drawable/publicloading&…