为什么懒汉式还存在
单例模式我们在项目中会经常使用到,有常见的懒汉式、饿汉式,很多人搞不懂饿汉式既然既是线程安全的又是不需要线程同步,为什么还会存在懒汉式呢?存在即是合理,就论需要在构造函数中传递参数而言(当然这里的参数是不变的,如果参数是可变的,那么每次创建的对象都不一样,那么之前创建的对象都没用,违背了单例模式的设计初衷),懒汉式做的就比饿汉式好。首先,我们以懒汉式为例,代码如下:
父类:
public class Father {
public Father(String s,int i){
System.out.println("s="+s);
System.out.println("i="+i);
}
}
主函数:
public class Main {
public static void main(String[] args) {
// TODO Auto-generated method stub
testSon();
testSonB();
testSonC();
}
public static void testSon(){
Son son=Son.getSonInstance("a", 1);
}
public static void testSonB(){
SonB sonb=SonB.getInstance("z", 2);
}
public static void testSonC(){
SonC sonc=SonC.getInstance("q", 3);
}
}
使用懒汉式的子类:
public class Son extends Father{
private static Son son;
private Son(String s, int i) {
super(s, i);
// TODO Auto-generated constructor stub
}
public static Son getSonInstance(String s,int i){
if(son==null){
synchronized (Son.class) {
son=new Son(s,i);
}
}
return son;
}
}
使用静态内部类方式的子类:
public class SonB extends Father{
private static String s;
private static int i;
private SonB() {
super(s, i);
// TODO Auto-generated constructor stub
}
private static class LoadSonB {
private static final SonB SONB_INTANCE=new SonB();
}
public static SonB getInstance(String s1,int i1){
s=s1;
i=i1;
return LoadSonB.SONB_INTANCE;
}
}
使用饿汉式方式的子类:
public class SonC extends Father{
private static String s;
private static int i;
public SonC() {
super(s, i);
// TODO Auto-generated constructor stub
}
private static SonC sonc=new SonC();
public static SonC getInstance(String s1,int i1){
s=s1;
i=i1;
return sonc;
}
}
输出结果:
s=a
i=1
s=z
i=2
s=null
i=0
从上面的结果可以看出,懒汉式和静态内部类的方式都可以在构造函数中像父构造函数传递值,而饿汉式不行,为什么?因为静态内部类在类加载的时候不会加载,静态内部类和非静态内部类一样,都是在被调用时才会被加载,而静态变量、静态方法、静态块都是在类加载的时候就已经”准备好了”,也就是可以被使用或者已经被执行,所以使用静态内部类方式的时候可以,因为,类加载的时候静态内部类还没加载,所以构造函数还没运行,当静态内部类被调用时,参数已经被赋值了,所以可以。而使用饿汉式,由于sonc属于static变量,而且在声明的时候new了,那时参数还没有赋值时,构造函数已经被调用了,所以不行。如果不能理解这里,可以看http://www.cnblogs.com/zhguang/p/3154584.html。
那么如果使用饿汉式怎么办呢?
答案是办不到,因为饿汉式需要在类加载的时候就生成对象,那个时候无法传递参数。当然,如果传递参数不是发生在构造函数中,那么就可以使用饿汉式,代码如下:
public class SonD {
private static String s;
private static int i;
public SonD() {
// TODO Auto-generated constructor stub
String s2=s;
System.out.println("s2"+s2);
}
private static SonD sond=new SonD();
public static SonD getInstance(String s1,int i1){
s=s1;
i=i1;
System.out.println("s1="+s);
System.out.println("i1="+i);
System.out.println("get");
return sond;
}
}
主函数:
public class Main {
public static void main(String[] args) {
// TODO Auto-generated method stub
testSonD();
}
public static void testSonD(){
SonD sond=SonD.getInstance("m", 4);
}
}
运行结果:
s2null
s1=m
i1=4
get
为什么这里s2=null呢?因为s是static,而且在声明的时候直接new了,所以值是null,因此,我们使用饿汉式的时候传递值是不能在构造函数中进行的,而要在别的地方,比如类SonD中的getInstance()方法中就行,这样就实现了使用饿汉式传递参数,不过注意这里的传递参数不是发生在构造函数中的,如果是构造函数需要传入参数,就要使用懒汉式,而且,使用饿汉式传递参数,不能在构造函数中传递(类SonD的输出结果证实这一点),现在是不是有些理解懒汉式为什么存在呢?其实,综上所述,使用单例模式的时候,最好使用内部类的方式来实现。