浅谈enum与单例设计模式_JAVA_编程开发_程序员俱乐部

中国优秀的程序员网站程序员频道CXYCLUB技术地图
热搜:
更多>>
 
您所在的位置: 程序员俱乐部 > 编程开发 > JAVA > 浅谈enum与单例设计模式

浅谈enum与单例设计模式

 2014/9/4 12:19:36  247687009  程序员俱乐部  我要评论(0)
  • 摘要:在JDK1.5之前的单例实现方式有两种(懒汉式和饿汉式并无设计上的区别故看做一种),两者同是私有构造器,导出静态成员变量,以便调用者访问。第一种packagesingleton;publicclassSingleton{//导出全局成员publicfinalstaticSingletonINSTANCE=newSingleton();//私有构造privateSingleton(){}}私有构造器只会被调用一次,用于构建Singleton类中的INSTANCE实例,由于构造器被私有化
  • 标签:模式 浅谈 设计 设计模式
在JDK1.5之前的单例实现方式有两种(懒汉式和饿汉式并无设计上的区别故看做一种),两者同是私有构
造器,导出静态成员变量,以便调用者访问。

第一种
class="java">package singleton;

public class Singleton {
        //导出全局成员
        public final static Singleton INSTANCE = new Singleton();
        //私有构造
        private Singleton(){}
}
?私有构造器只会被调用一次,用于构建Singleton类中的INSTANCE 实例,由于构造器被私有化,并且没
有其他公开的构造器,所有能够保证在app中只会有一个Singleton实例。

  真的是我们想的那样只会存在一个么?答案是否定的,可以使用java反射包提供的setAccessible()
方法去掉权限检查即可构造出实例对象

使用反射构造单例对象
      final Constructor<?>[] constructors = Singleton.class.getDeclaredConstructors();
                for (Constructor<?> constructor : constructors) {
                        //忽略检查
                        constructor.setAccessible(false);
                        //构造对象实例
                        final Object newInstance = constructor.newInstance();
                        
                        System.out.println(newInstance == Singleton.INSTANCE); //false
                }
?现在单例类被反射轻松攻破了吧。

 再看第二基于工厂方法的单例
package singleton;

public class Singleton {
        //导出全局成员
        private  final static Singleton INSTANCE = new Singleton();
        //私有构造
        private Singleton(){}
        public static final Singleton getInstance(){
                return INSTANCE;
        }
}
? 该方式与第一种差别并不大,工厂方法的优势在于灵活性,在不改变API的前提下,我们可以修改该类
是否为单例,还是为每一个线程构建一个实例对象。同第一中方式相同也存在反射攻击的可能性,为了
防止反射攻击,需要对私有构造进行改写

package singleton;

import java.lang.reflect.Constructor;

public class Singleton {
        //导出全局成员
        public final static Singleton INSTANCE = new Singleton();
        //私有构造
        private Singleton(){
                if (null != INSTANCE) {
                        throw new IllegalArgumentException("不能存在两个实例对象");
                }
        }
        
        public static void main(String[] args) throws Exception {
                final Constructor<?>[] constructors = Singleton.class.getDeclaredConstructors();
                for (Constructor<?> constructor : constructors) {
                        //忽略检查
                        constructor.setAccessible(false);
                        //构造对象实例 此时这里回抛出异常
                        final Object newInstance = constructor.newInstance();
                        System.out.println(newInstance == Singleton.INSTANCE);
                }
        }
?这样子也可以就可以保证不受反射的攻击啦。
 
 在JDK1.5之后的版本提供了枚举关键字,提供了更加方便的单例创建方式
public enum Singleton {
        INSTANCE;
}
?三句代码搞定一个单例,并且无偿的提供序列化机制,绝对防止多实例的存在。
 以上两种方式如果序列化,仅仅是实现serialiazble接口是不够的,为了维护和保证Singleton请提供
一个方法
    public Singleton redResolve(){
                return INSTANCE;
        }
?
发表评论
用户名: 匿名