要解决的问题
让一个类在内存中只有一个对象。
问题的由来
1.对于系统中的某些类来说只有一个实例很重要。
windows中只能打开一个任务管理器窗口。如果不使用机制对窗口对象进行唯一化,就会有我每点击一下按钮就出现一个任务管理器窗口这样的现象。如果这些窗口显示的内容完全一致,则是重复对象,浪费内存资源;如果内容不一致,则意味着在某一瞬间系统有多个状态,与实际不符。
2.对于一些需要频繁创建的对象,用单例模式可以节约系统资源。
如何保证对象的唯一性
1.为了避免其他程序过多建立该类对象,先禁止其他程序建立该类对象
2.还为了让其他程序可以访问到该类对象,只好在本类中,自定义一个对象。
3.为了方便其他程序对自定义对象的访问,可以对外提供一些访问方式。
这三步怎么用代码实现?
1.将构造函数私有化
2.在类中创建一个本类对象
3.提供一个方法可以获取到该对象。
饿汉式单例模式
class Single()
{
private Singel(){}//将构造函数私有化
private static Single s=new Singel();
public static Singel getInstance()
{
return s;
}
}
class SingleDemo
{
public static void main(String[] args)
{
Single ss=Single.getInstance();
Single sss=Single.getInstance();
}
}
先将构造函数私有化,这样在其他类中就不能使用new来创建他的对象。
创建一个Single类型的变量s来存储创建的Single对象,这个变量不必让外界知道,所以加上private修饰符。
private Singel s=new Singel();
创建一个公开的方法来返回这个对象
public Singel getInstance()
{
return s;
}
方法要么通过对象来调用,要么通过类名来调用。现在不能创建对象了,只能通过类名调用。所以这个方法应该静态方法。
在本类中静态方法只能访问静态成员,所以s也应该为静态的。
第一调用Single.getInstance();的时候,先加载类,创建对象,将对象的地址赋给s,再调用getInstance方法再将地址赋给ss。
第二次调用的时候,内存中已经存在s了,直接将地址赋给sss就行了。(这就省去了频繁创建对象的过程)。
光写这几句话没什么意义,对事物该怎么描述的时候还怎么描述,只是当需要保证事物的对象在内存中唯一时,将这三步加上即可。
懒汉式单例模式
class Single
{
private Single(){}
private static Single s=null;
public static Single getInstance()
{
if(s==null)
s=new Single();
return s;
}
}
这种写法,当一个程序来调用,不会出现问题。但当多个程序调用的时候就可能出现问题。
比如A程序在执行了if(s==null)后,判断为null,本来应该接着执行,但cpu又去执行别的程序了(cup一个时刻只能执行一个程序,只不过是cup切换程序的速度很快,用户感觉不到)。
之后B在执行了if(s==null)后,判断为null,本来应该接着执行,cup又切换到了A程序接着往下执行,创建了Single对象。之后cup又切换到了B,B接着执行,又创建了一个对象。这时候对象已经不唯一了。
class Single
{
private Single(){}
private static Single s=null;
public static synchronized Single getInstance()
{
if(s==null)
s=new Single();
return s;
}
}
可以添加synchronized关键字来吧这段程序锁起来,即使A程序执行到if(s==null),cpu切换了出去。因为加了锁,B也进不来。
但是这时程序的效率就低了,不管s是否为null,之前我都要判断是否锁着呢。
class Single
{
private Single(){}
private static Single s=null;
public static Single getInstance()
{
if(s==null)
{
synchronized(Single.class)
{
if(s==null)
s=new Single();
}
}
return s;
}
}
这样为s为空的时候才判断锁,减少了判断次数。
总结
饿汉式是Single类一进内存就已经创建好了对象。
懒汉式(也叫对象的延迟加载),在Single进内存的时候,对象还没有存在,只有调用了getInstance方法时,才建立了对象。
开发的时候用饿汉式,简单,安全(方法里就一句话,涉及不到多线程)。懒汉式面试的时候问的多。
玩儿单例模式就是为了用那个唯一对象,获取对象是首先要做的事,有了对象才能调用其它的方法。先创建后创建早晚都要加载。