面试常客,单例模式实现解析

在java代码中单例模式是很常用的一种设计模式,其实现形势也是多样的,但你真的了解什么是单例吗?这个问题也经常在面试中出现,那么让我们一起来学习一下吧!

首先,为什么要用单例?
你可能会说:只创建一次对象;emmmm…. 然后就不知道了。。
OK, 在我没有查资料之前我好像知道就比这个多一点,需要线程安全。
那么补充:(借鉴他人)

延迟加载
线程安全
没有性能问题
防止序列化产生新对象
防止反射攻击

那下面就围绕这些点来探讨单例实现方法吧!

android 单例实现方法:

一、枚举方法

public enum Singleton{  
        INSTANCE;  
    } 

枚举的特性已经实现了单例,也可以保证线程安全,而且还解决了反序列化和反射攻击。
看到这里你是不是觉得 哇!这么好,而且代码还这么少,我就用这个了。哈哈,别急给你看个文章

二、饿汉式 (有诸多缺陷,注意看优化方案)
先看示例:

public class Singleton {  
    private static final Singleton INSTANCE = new Singleton();  
    // 私有构造函数  
    private Singleton(){}  

    public static Singleton getInstance(){  
        return INSTANCE;  
    }  
}  

当你看到这个方式是不是眼前一亮,哟!这个我能看出来,实现了单例。
慢着,再仔细看看,这个方法直接在类里写静态方法new出来Singleton对象,这样不管你需不需要都会new出来,这就不是我们想要的懒加载了;而且当实现Serializable接口后,反序列化时单例会被破坏。

看优化版本:

public class Singleton implements Serializable {  
    private static final Singleton INSTANCE = new Singleton();  
    // 私有化构造函数  
    private Singleton(){}  

    public static Singleton getInstance(){  
        return INSTANCE;  
    }  

    /** 
     * 如果实现了Serializable, 必须重写这个方法 
     */  
    private Object readResolve() throws ObjectStreamException {  
        return INSTANCE;  
    }  
}  

这里就解决了序列化后,单例依然能用的问题。

三、懒汉式 (面试重点 也是最能体现技术的)

当前用的最多的,也最体现技术的;
懒汉式也是对饿汉式的一种优化,实现了延迟加载,但其本身还需要进一步优化,故成为面试被问的最多的点。

示例代码:

public static Singleton getSingleton() {  
    if (INSTANCE == null) {               // 第一次检查  
        synchronized (Singleton.class) {  
            if (INSTANCE == null) {      // 第二次检查  
                INSTANCE = new Singleton();  
            }  
        }  
    }  
    return INSTANCE ;  
}  

这样,代码看起来是很合理了已经,但是看这里大神的分析

四、内部类实现 (具体看帖子)

内部类实现的方法就比较简单了,看示例:

public class Singleton {   
    /**  
     * 类级的内部类,也就是静态的成员式内部类,该内部类的实例与外部类
     * 的实例没有绑定关系
     * 而且只有被调用到才会装载,从而实现了延迟加载  
     */   
    private static class SingletonHolder{   
        /**  
         * 静态初始化器,由JVM来保证线程安全  
         */   
       private static final Singleton instance = new Singleton();   
    }   
    /**  
     * 私有化构造方法  
     */   
    private Singleton(){   
    }   

    public static  Singleton getInstance(){   
        return SingletonHolder.instance;   
    }   
}  

使用内部类的方法,在外部类被调用的时候,Singleton这个类不会被调用,所以实例就实现了延迟加载,只有getInstance方法被调用时,才会初始化instance。同时,由于实例的建立是时在类加载时完成,故天生对多线程友好,getInstance() 方法也无需使用同步关键字。

能看到这里,整个单例就差不多。注意:学习单例不能只看代码是怎么写的,这里边涉及到jvm虚拟机加载class类的机制,程序执行机制,性能问题等。所以,还是要多看原理。加油吧!!

猜你喜欢

转载自blog.csdn.net/gaoshang0304/article/details/78328644
今日推荐