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

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

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,一经查实,立即删除!

相关文章

java web开发之 spring单元测试

以前开发web项目从来不喜欢用单元测试&#xff0c;每次都需要启动服务器&#xff0c;在浏览器中调试&#xff0c;有些错误还不一定发现得到。 最近公司开发一个项目&#xff0c;任务繁重&#xff0c;不由觉得以前那种测试模式太笨拙了&#xff0c;于是学习了使用Junit&#xf…

对于SpringMVC框架使用的时候出现“警告: No mapping found for HTTP request with URI [/login]”的问题解决方案...

今天&#xff0c;在myeclipse上导入了前几天的一个项目&#xff0c;但是怎么都运行不起来&#xff0c;可是在别人的电脑上都可以。从早上一直调到了现在&#xff08;期间也看了好多关于此类的帖子&#xff0c;但是都没能解决我的问题&#xff09;&#xff0c;终于找到了解决方案…

MySQL数据库事务中的行级锁,表级锁,页级锁

锁定用于确保事务完整性和数据库一致性。 锁定可以防止用户读取其他用户正在更改的数据&#xff0c;并防止多个用户同时更改相同的数据。 如果不使用锁定&#xff0c;数据库中的数据可能在逻辑上变得不正确&#xff0c;而针对这些数据进行查询可能会产生想不到的结果。 在计算机…

#error

#define SIZE 250 #if SIZE<1 || SIZE>200 #error "SIZE must be between 1 and 200" #endif转载于:https://www.cnblogs.com/guxuanqing/p/4892802.html

搭建spring MVC项目

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

换行的css属性

//正常换行word-break:keep-all;word-wrap:normal;//下面这行是自动换行word-break:break-all;word-wrap:break-word;word-wrap:normal | break-word; (内容换行)normal:默认的属性值.&#xff08;允许内容顶开指定的容器边界&#xff09;.break-word:内容将在边界内换行(不截断…

基于jquery.ajax的进一步封装

这是最近写项目用到的一个小功能&#xff0c;给大家分享下&#xff0c;希望对大家有帮助。 直接上代码&#xff1a; % page language"java" contentType"text/html; charsetUTF-8" pageEncoding"UTF-8"%> <!DOCTYPE html PUBLIC &quo…

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…

pigeon服务

点击打开链接

使用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"></…

JQ调用后台方法

首先&#xff0c;先在页面上创建一个asp按钮&#xff0c;添加点击事件&#xff0c;把要在前台调用的后台方法写在这个按钮的点击事件中&#xff1a; <span style"display:none;"><asp:Button ID"btnSelectCategory" runat"server" type…

如何理解HTTP协议的 “无连接,无状态” 特点?

转载自&#xff1a;点击打开链接http://blog.csdn.net/tennysonsky/article/details/44562435 HTTP 是一个属于应用层的面向对象的协议&#xff0c;HTTP 协议一共有五大特点&#xff1a;1、支持客户/服务器模式&#xff1b;2、简单快速&#xff1b;3、灵活&#xff1b;4、无连接…

jqgrid使用

1.准备工作 首先&#xff0c;要引入基本的jquery文件&#xff0c;然后是下载jqgrid插件&#xff0c;我这里引入的有jquery.jqGrid.src.js,grid.setcolumns.js,grid.locale-en.js,jqgrid.css,ui.multiselect.css. 2.创建用来承载jqgrid的标签 <table id"gridTable"…

“睡服”面试官系列第一篇之let和const命令(建议收藏学习)

目录 1let命令 1.1基本用法 1.2for循环小案例 1.3不存在变量提升 1.4暂时性死区 1.5不允许重复声明 2块级作用域 2.1为什么需要块级作用域&#xff1f; 2.2ES6 的块级作用域 2.3块级作用域和函数声明 3const 3.1本质 4顶层对象的属性 5global对象 6总结 1let命令…

Java命名规范和代码风格

Java命名规范和代码风格 基本命名规范 包命名 包名按照域名的范围从大到小逐步列出&#xff0c;恰好和Internet上的域名命名规则相反。 由一组以“.”连接的标识符构成&#xff0c;通常第一个标识符为符合网络域名的两个或者三个英文小写字母。 例:cn.edu.xupt.JavaTest 类&…

jqgrid多选和禁止某行记录选择

在对一些特殊数据&#xff0c;我们总是要做一些防范手段。 在jqgrid中添加了多选属性后&#xff0c;默认是每一行都能自由选择。有时候&#xff0c;一些数据不满足某些情况是不让选中处理的。 怎么实现&#xff1f; 直接上代码&#xff1a; onSelectAll:function(rowid, status…

SYN 攻击原理以及防范技术

转载自&#xff1a;http://netsecurity.51cto.com/art/200608/30428.htm 据统计&#xff0c;在所有黑客攻击事件中&#xff0c;SYN攻击是最常见又最容易被利用的一种攻击手法。相信很多人还记得2000年YAHOO网站遭受的攻击事例&#xff0c;当时黑客利用的就是简单而有效的SYN攻击…

使用adb调试android

原来以为真机调试android应用只能用数据线连接手机&#xff0c;后来在公司经前辈推荐&#xff0c;发现adb wireless这个工具不错&#xff0c;只需要将该apk安装到设备上&#xff0c;然后和电脑连同一无线网&#xff0c;打开该工具&#xff0c;看到为设备分配了Ip地址就代表可以…

总结css中单位px和em,rem的区别

国内的设计师大都喜欢用px&#xff0c;而国外的网站大都喜欢用em和rem&#xff0c;那么三者有什么区别&#xff0c;又各自有什么优劣呢&#xff1f; PX特点 1. IE无法调整那些使用px作为单位的字体大小&#xff1b; 2. 国外的大部分网站能够调整的原因在于其使用了em或rem作为字…

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

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