单例模式
单例模式,是设计模式中的一种。
单例模式,其特点是:被设计为单例的类型,在同一时间内,该类型的对象只会存在1个!
假设存在King
类:
public class King {}
作为一个普通的类,是可以在类的外部随意创建对象的,例如:
King k1 = new King();
King k2 = new King();
King k3 = new King();
因为在King
类中,没有声明构造方法,则编译器会自动的添加默认构造方法,也就是公有的、无参数的构造方法,所以,在类的外部才可以随意创建对象!以上代码中就创建了3个King
类型的对象!
如果要实现单例,首先,就不能允许随意创建对象,可以显式的添加构造方法,并将其私有化,避免外部随意访问,例如:
public class King {
private King() {}
}
一旦显式的添加了构造方法,编译器就不会再自动添加构造方法了,则在类的外部,将不可以再执行King k1 = new King();
这类的代码了!
使用了私有的构造方法,并不影响在类的内部使用该构造方法,为了保证在类的外部依然可以获取类的对象,则可以:
public class King {
private King() {}
public King getInstance() {
return new King();
}
}
同时,为了保证“多次获取时,获取到的都是同一个对象”,则不能反复在方法中创建对象,而是改为:
public class King {
private King king = new King();
private King() {}
public King getInstance() {
return king;
}
}
改为这样以后,无论执行多少次getInstance()
方法,该方法返回的都是同一个king
变量,而该变量的值只是在类被加载时赋值了1次而已,就实现了单例的效果!
当然,以上代码是矛盾的!因为,如果要调用getInstance()
方法,必须先有King
类型的对象,而得到King
类型对象的唯一途径就是调用getInstance()
方法!也就是说:不调用getInstance()
方法就无法得到对象,但是,调用方法之前又必须有对象!
为了解决这个问题,可以为getInstance()
方法添加static
修饰符,则通过类名.方法名()
的格式就可以调用方法了,不需要事先获取对象!同时,基于“被static
修饰的成员不可以直接访问没被static
修饰的成员”的原则,所以,全局的private King king = new King();
也需要添加static
修饰符:
public class King {
private static King king = new King();
private King() {}
public static King getInstance() {
return king;
}
}
至此,简单的单例模式代码就完成了,后续,需要获取King
类型的对象时,只能通过King.getInstance()
得到对象,而该方法每次返回的都是同一个对象!
严格来说,以上单例模式得设计是“饿汉式”的,可以看到,在类被加载时,就直接创建了King类的对象,此时,也许并不需要获取对象,,后续当需要对象时,直接获取即可。还有一种是“懒汉式”的单例模式,其特点就是“不到逼不得已,不创建对象”!基础代码例如:
public class King {
private static King king;
private King() {}
public static King getInstance() {
if(king == null){
king = new King();
}
return king;
}
}
以上代码是多线程不安全的!为了解决这个问题,可以将以上代码快添加互斥锁,例如:
public class King {
private static King king;
private King() {}
public static King getInstance() {
synchronized (“java”) {
if(king == null){
king = new King();
}
}
return king;
}
}
一旦添加了锁,每次调用getInstance()方法时都会先锁定代码再执行,效率偏低,为此,还可以这样:
public class King {
private static King king;
private King() {}
public static King getInstance() {
if(king==null){
synchronized (“java”) {
if(king == null){
king = new King();
}
}
}
return king;
}
}
以上,就是完整的“懒汉式”单例模式!
注意:被static
修饰的成员都是常驻内存的!