在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类的机制,程序执行机制,性能问题等。所以,还是要多看原理。加油吧!!