当前位置: 移动技术网 > IT编程>开发语言>Java > 用私有构造器或者枚举类型强化Singleton

用私有构造器或者枚举类型强化Singleton

2019年05月09日  | 移动技术网IT编程  | 我要评论

参考effective java第三版 joshua j. bloch

参与编写jdk的大佬,上次看collections的源码时看见了他的名字,然后翻了翻书,竟然就是他写的!

1.常见的一种:

public class singleton {
private static final singleton instance=new singleton();
private singleton(){ //如果没有判断,可以通过反射使用构造函数创建对象,然后就不是单例了 if (instance!=null){ //throw exception } }
public static singleton getinstance(){ return instance; }
public void dosomething(){ //... } }

通过反射:可以看到singleton的两个实例不是同一个。

class main {
public static void main(string[] args) { testsingleton(); }

   private static void testsingleton() {
singleton s1 = singleton.getinstance(); class<singleton> clazz = singleton.class; try { constructor<singleton> constructor = clazz.getdeclaredconstructor(new class[]{}); constructor.setaccessible(true); singleton s2 = constructor.newinstance(new class[]{}); system.out.println(s1 == s2); } catch (nosuchmethodexception e) { e.printstacktrace(); } catch (illegalaccessexception e) { e.printstacktrace(); } catch (instantiationexception e) { e.printstacktrace(); } catch (invocationtargetexception e) { e.printstacktrace(); } } }

2.用枚举:推荐的方法

优点:引用effective java的话:简洁,无偿的提供了序列化机制,绝对防止多次实例化,即使是在面对复杂的序列化或者反射攻击的时候。单元素的枚举类常是实现singleton的最佳方法。如果singleton必须扩展一个超类,而不是扩展enum时,不适宜使用这个方法。

public enum enumsingleton {
instance; public void dosomething(){ //... } }

 按照第一个测试的时候会报错的。

3.序列化

序列化有个问题就是,反序列化时会创建一个新的实例,破坏单例,下面让原来那个类实现serializable接口。

public class singleton implements serializable {

    private static final singleton instance=new singleton();

    private singleton(){
        if (instance!=null){
            try {
                throw new exception("instance已存在!");
            } catch (exception e) {
                e.printstacktrace();
            }
        }
    }

    public static singleton getinstance(){
        return instance;
    }

    public void dosomething(){
        //...
    }
}

测试一下:effective java的第9条 使用try-with-resources优于try-finally,关闭资源的时候。

private static void testserializablesingleton() {
file file=new file("singleton.out"); try(objectoutputstream out=new objectoutputstream(new fileoutputstream(file)); objectinputstream in=new objectinputstream(new fileinputstream(file))){ out.writeobject(singleton.getinstance()); singleton singleton= (singleton) in.readobject(); system.out.println(singleton == singleton.getinstance()); } catch (filenotfoundexception e) { e.printstacktrace(); } catch (ioexception e) { e.printstacktrace(); } catch (classnotfoundexception e) { e.printstacktrace(); } }

打印的结果是false,说明序列化破化了单例,因为反序列化是反射调用了无参构造函数。

解决方法:在类里加入这个方法,详见effective java第89条

private object readresolve() {
        return instance;
}

然后结果就是true了。

如对本文有疑问, 点击进行留言回复!!

相关文章:

验证码:
移动技术网