网站域名改版怎么做,门户网站 建设 北京 航天,js网站开发,自己制作一个网站本文转载自#xff1a;点击打开链接 Inspired by Effective Java. Singleton模式是在编程实践中应用最广泛的几种设计模式之一。以前知道的#xff0c;实现单例的方法有两种(下面的A、B)。刚刚在读《Effective Java的时候》学到一种新的更好的方法(E)#xff1a;单元素的枚举…本文转载自点击打开链接 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绿眉绿眼的望着。。。”); } } CallMaYun.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绿眉绿眼的望着。。。”); } } CallMaYun.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绿眉绿眼的望着。。。”); } CallMaYun.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; } } Featurejdk1.5之后才能正常达到单例效果。 E.编写一个包含单个元素的枚举类型[极推荐]。 代码如下 public enum MaYun { himself; //定义一个枚举的元素就代表MaYun的一个实例 private String anotherField; MaYun() { //MaYun诞生要做的事情 //这个方法也可以去掉。将构造时候需要做的事情放在instance赋值的时候 /** himself MaYun() { * //MaYun诞生要做的事情 * } **/ } public void splitAlipay() { System.out.println(“Alipay是我的啦看你丫Yahoo绿眉绿眼的望着。。。”); } } CallMaYun.himself.splitAlipay(); Feature:从Java1.5开始支持无偿提供序列化机制绝对防止多次实例化即使在面对复杂的序列化或者反射攻击的时候。 总之五类懒汉恶汉双重校验锁静态内部类枚举。 恶汉因为加载类的时候就创建实例所以线程安全(多个ClassLoader存在时例外)。缺点是不能延时加载。 懒汉需要加锁才能实现多线程同步但是效率会降低。优点是延时加载。 双重校验锁麻烦在当前Java内存模型中不一定都管用某些平台和编译器甚至是错误的因为instance new MaYun()这种代码在不同编译器上的行为和实现方式不可预知。 静态内部类延迟加载减少内存开销。因为用到的时候才加载避免了静态field在单例类加载时即进入到堆内存的permanent代而永远得不到回收的缺点(大多数垃圾回收算法是这样)。 枚举很好不仅能避免多线程同步问题而且还能防止反序列化重新创建新的对象。但是失去了类的一些特性没有延迟加载用的人也太少了 以后多推广推广单元素枚举这种更好的单例实现方式。在项目中的代码开始修改实施 下面小demo示范一下这是只有一个元素的枚举类枚举类里面也可以写方法。 [java] view plaincopy package go.derek; public enum EnumSingleton { instance; public void doSomething(){ System.out.println(do something); } } 测试类如下 [java] view plaincopy package go.derek; import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; public class Test { public static void main(String[] args) throws InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException { Constructor?[] array EnumSingleton.class.getDeclaredConstructors(); for (Constructor? c : array){ c.setAccessible(true); //此处会抛出异常 c.newInstance(); } } } 运行结果如下 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) 可见不能通过反射来创建枚举对象所以这种单例模式可以抵御恶意客户端通过反射的攻击。此外枚举类的单例模式也不必担心反序列化的时候多次创建实例。