------- android培训、java培训、期待与您交流! ----------
单例设计模式
java中单例模式是一种常见的设计模式,单例模式分三种:懒汉式单例、饿汉式单例、登记式单例三种。
一、饿汉式
1、设计模式:解决某一类问题最行之有效的方法。java中有23种设计模式。
单例设计模式:解决一个类在内存只存在一个对象。
2、想要保证对象唯一。
1,为了避免其他程序过多建立该类对象,先禁止其他程序建立该类对象。
2,还为了让其他程序可以访问到该类对象,只好在本类中,自定义一个对象。
3,为了方便其他程序对自定义对象的访问,可以对外提供一些访问方式。
3、这三步怎么用代码体现呢?
1,将构造函数私有化。
2,在类中创建一个本类对象。
3,提供一个方法可以获取到该对象。
对于事物该怎么描述,还怎么描述。当需要将该事物的对象保证在内存中唯一时,就将以上的三步加上即可。
这个是先初始化对象。称为:饿汉式。Single类一进内存,就已经创建好了对象。
记住原则:定义单例,建议使用饿汉式。
class Single
{
private Single(){} //1,将构造函数私有化。
private static Single s=new Single(); //2,在类中创建一个本类对象。
public static Single getInstance() //3,提供一个方法可以获取到该对象。
{
return s;
}
}
饿汉式在类创建的同时就已经创建好一个静态的对象供系统使用,以后不再改变,所以是线程安全的。
例如:
class Single
{
private int num;
public void setNum(int num)
{
this.num=num;
}
public int getNum()
{
return num;
}
private Single(){} //1,将构造函数私有化。
private static Single s=new Single(); //2,在类中创建一个本类对象。
public static Single getInstance() //3,提供一个方法可以获取到该对象。
{
return s;
}
}
class SingleDemo
{
public static void main(String[] args)
{
Single s1=Single.getInstance();
Single s2=Single.getInstance();
s1.setNum(23);
System.out.println(s2.getNum());
}
}
二、懒汉式
对象是方法被调用时,才初始化,也叫做对象的延时加载。称为:懒汉式
Single类进内存,对象还没有存在,只有调用了getInstance方法时,才建立对象。
class Single
{
private static Single s=null;
private Singel(){}
public static Single getInstance()
{
if(s==null)
s=new Single();
return s;
}
}
例如:
//懒汉式优化后
class Single
{
private static Single s=null;
private Singel(){}
public static Single getInstance()
{
if (s==null)
{
synchronized(Single.class) //synchronized,同步的意思
{
if(s==null)
s=new Single();
}
}
return s;
}
}
三、登记式单例
//类似Spring里面的方法,将类名注册,下次从里面直接获取。
public class Singleton3 {
private static Map<String,Singleton3> map = new HashMap<String,Singleton3>();
static{
Singleton3 single = new Singleton3();
map.put(single.getClass().getName(), single);
}
//保护的默认构造子
protected Singleton3(){}
//静态工厂方法,返还此类惟一的实例
public static Singleton3 getInstance(String name) {
if(name == null) {
name = Singleton3.class.getName();
System.out.println("name == null"+"--->name="+name);
}
if(map.get(name) == null) {
try {
map.put(name, (Singleton3) Class.forName(name).newInstance());
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
return map.get(name);
}
//一个示意性的商业方法
public String about() {
return "Hello, I am RegSingleton.";
}
public static void main(String[] args) {
Singleton3 single3 = Singleton3.getInstance(null);
System.out.println(single3.about());
}
}
登记式单例实际上维护了一组单例类的实例,将这些实例存放在一个Map(登记薄)中,对于已经登记过的实例,则从Map直接返回,对于没有登记的,则先登记,然后返回。
饿汉式和懒汉式区别
1、线程安全:
饿汉式是线程安全的,可以直接用于多线程而不会出现问题,懒汉式就不行,它是线程不安全的,如果用于多线程可能会被实例化多次,失去单例的作用。
如果要把懒汉式用于多线程,有两种方式保证安全性,一种是在getInstance方法上加同步,另一种是在使用该单例方法前后加双锁。
2、资源加载:
饿汉式在类创建的同时就实例化一个静态对象出来,不管之后会不会使用这个单例,会占据一定的内存,相应的在调用时速度也会更快,
而懒汉式顾名思义,会延迟加载,在第一次使用该单例的时候才会实例化对象出来,第一次掉用时要初始化,如果要做的工作比较多,性能上会有些延迟,之后就和饿汉式一样了。