欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

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

程序员文章站 2024-01-05 16:00:10
Effective Java第3条中的Singleton的实现。 ......

参考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了。

上一篇:

下一篇: