我们要明白why?为什么要用单例? where?单例用在什么地方?这个问题请在文末寻找。先看怎么来写单例。
特点
单例类只能有一个实例
单例类必须自己创建自己的唯一实例
单例类必须给所有其他对象提供这一实例
写法
/**
* 懒汉式单例
* @author qian.cheng
*
*/
public class SingletonHungry {
//私有无参构造方法,保证除此类外通过实例化无法获取实例
private SingletonHungry(){}
//需要时再新建实例
private static SingletonHungry singletonHungry;
//返回该单例实例
public static synchronized SingletonHungry getInstance() {
if(singletonHungry==null) {
singletonHungry=new SingletonHungry();
}
return singletonHungry;
}
}
/**
* 饿汉式单例
* @author qian.cheng
*
*/
public class SingletonLazy {
//私有无参构造方法,保证除此类外通过实例化无法获取实例
private SingletonLazy(){}
//在程序启动时就初始化,一直存在内存中
private static final SingletonLazy SINGLETON_LAZY=new SingletonLazy();
//返回该单例实例
public static synchronized SingletonLazy getInstance() {
return SINGLETON_LAZY;
}
}
为什么叫饿汉懒汉呢?
饿汉式每次调用的时候不用做创建,直接返回已经创建好的实例。这样虽然节省了时间,但是却占用了空间
懒汉式第一次调用创建,以后之后返回第一次创建的实例,在一次创建的时候会慢一些。节省了空间,占用了时间
那么为什么我们要使用单例模式呢?
原因1:
因为我们知道内存分为堆内存和栈内存,A a=new A();栈内存里的是A对象的索引变量a,而a变量持有的A对象在堆内存。如果a一直持有对象A的引用,导致GC无法回收,就会引起内存泄漏,而我们上文提到的单例模式的特点完美解决了这一点。
原因2:
如果我们操作非单例模式的属性时,可能会出现数据错乱,举个栗子。
public class SingletonTest {
static class A{
int i=0;
}
public static void main(String[] args) {
A a1=new A();
a1.i++;
A a2=new A();
System.out.println(a2.i);
}
}
打印结果为0,为什么呢,我是把A的i加1,之后再打印就变成0了?because 我们操作的是a1对象的i属性,而我们打印的是a2对象的i值。
public class SingletonTest {
static class A{
int i=0;
}
public static void main(String[] args) {
A a1=new A();
a1.i++;
A a2=new A();
System.out.println(a1.i);
}
}
我们打印一下a1的值,是1.
什么地方调用单例模式呢?
像windows系统的回收站,手机和电脑的文件管理系统,同一时刻只能有一个访问,而且只允许存在一个对象。还有安卓的全局Context等等