今天买了《大话设计模式》这本书,也是找朋友推荐的。晚上拿到手,就看了一下单例模式这一章,因为自己只是知道单例模式,其它模式完全不懂,就想看看这本书是不是真的读起来容易理解以及讲的怎么样。一个小时看完这一章节,觉得还可以吧,讲的东西是很容易理解,且循序渐进,虽然讲的东西自己基本都是知道的,因为之前就了解这个模式。接下来还要把其它模式研究一下,继续努力~~~
关于单例模式,补充一下自己曾经遗漏的知识点:
1、单例模式不仅仅要保证一个类在内存中只存在一个实例,而且提供一个它的全局访问点(而且这里是之前自己模糊的地方)。
2、如何保证一个类的全局实例变量不被实例化多次?
最好的方式就是:让类自身来保存它的唯一实例 。
这个类可以保证以下两点:(1)这个全局实例变量只被实例化一次。
(2)提供一个访问这个全局实例变量的public方法。
3、单例 VS 实用类的静态方法
相同点:实用类也经常使用private的实例构造器方法,从而避免创建其它类创建它的实例。
不同点:(1)实例类不保存状态,比如,你不会去判断它是否为null,然后再去调用它的方法;但是单例是有状态的,单例的创建过程就是先判断是否为null,然后才确定要不要创建它的实例。
(2)实用类不能被继承(你没见过有类继承Math类吧,因为它是final类型的);单例类可以被子类继承。
(3)实用类仅仅是一些方法、属性的集合;单例有自己的对象实例。
4、单例的初始化时间
根据单例的初始化时间,单例类可以被饿汉式单例类和懒汉式单例类。
4.1、饿汉式单例类:在类初始化式,分配内存;
4.1.1、这可以通过两种方式实现:
4.1.1、静态初始化。从JVM角度分析,就是在执行静态代码时,被初始化。
4.1.2、构造器方式。这需要将作为实例变量单例的实例化代码写在类的构造函数里面。也就是在执行完类的静态代码后,再执行类的构造器函数时,创建单例实例。
4.1.3、缺点:会提前占用内存。通过静态初始化方式,在类未被实例化时,就为单例分配内存空间。通过构造器方式,在类实例化时,为单例分配内存空间。
懒汉式单例类:
4.2.1、懒汉式单例类:在单例被第一次调用时,分配内存;
5、测试code:
5.1、懒汉式1
/**version1 未考虑多线程安全问题 && 懒汉式
**/
class SingleTon{
private static SingleTon singleTon=null;
private SingleTon(){}
public static SingleTon getSingleTon(){
if(singleTon==null){
singleTon=new SingleTon();
}
return singleTon;
}
}
public class Main{
public static void main(String[] args) throws Exception {
SingleTon s1=SingleTon.getSingleTon();
SingleTon s2=SingleTon.getSingleTon();
System.out.println(s1==s2);//true,说明二者内存地址相同,所以二者肯定是同一个对象,所以保证了类的单例存在
}
}
5.2、懒汉式2
/**version2 考虑多线程安全问题 && 懒汉式
**/
class SingleTon{
private static SingleTon singleTon=null;
private SingleTon(){}
synchronized public static SingleTon getSingleTon(){
if(singleTon==null){
singleTon=new SingleTon();
}
return singleTon;
}
}
public class Main{
public static void main(String[] args) throws Exception {
SingleTon s1=SingleTon.getSingleTon();
SingleTon s2=SingleTon.getSingleTon();
System.out.println(s1==s2);//true,说明二者内存地址相同,所以二者肯定是同一个对象,所以保证了类的单例存在
}
}
5.3、饿汉式(4.1.1)
/**version3 饿汉式(类构造器clinit()初始化时,分配内存)
**/
class SingleTon{
private static SingleTon singleTon=new SingleTon();
private SingleTon(){}
public static SingleTon getSingleTon(){
return singleTon;
}
}
public class Main{
public static void main(String[] args) throws Exception {
SingleTon s1=SingleTon.getSingleTon();
SingleTon s2=SingleTon.getSingleTon();
System.out.println(s1==s2);//true,说明二者内存地址相同,所以二者肯定是同一个对象,所以保证了类的单例存在
}
}
5.4、饿汉式(4.1.2)
/**version4 饿汉式(实例构造器初始化时,分配内存)
**/
class SingleTon{
private static SingleTon singleTon=null;
private SingleTon(){
singleTon=new SingleTon();
}
public static SingleTon getSingleTon(){
return singleTon;
}
}
public class Main{
public static void main(String[] args) throws Exception {
SingleTon s1=SingleTon.getSingleTon();
SingleTon s2=SingleTon.getSingleTon();
System.out.println(s1==s2);//true,说明二者内存地址相同,所以二者肯定是同一个对象,所以保证了类的单例存在
}
}
参考资料:《大话设计模式》程杰 p209-p219