设计模式之单例

单例模式就是存在一个实例。这个实例在整个应用中只存在一个。接下来我就演示下几种常见的单例:

1 饿汉模式

饿汉模式就是类一加载,该实例就创建了,

public class SingleSimple {
    /**
     * private代表是不向外部暴露出去,
     */
    private static SingleSimple single=new SingleSimple();
    private SingleSimple(){}//private代表不能new创建该实例。必须为private

    public static SingleSimple newInstance(){

        return single;
    }
}

这就是一个简单的饿汉单例。

然后测试下:

public class SingleSimpleTest {

    public static void main(String[] args) {

        SingleSimple single01=SingleSimple.newInstance();
        SingleSimple single02=SingleSimple.newInstance();

        System.out.println(single01==single02);
    }

}

运行结果:
这里写图片描述

可以看到,运行结果为true,这就说明single01和single02是指向内存中同一个。

2 懒汉模式(线程不安全)

懒汉模式是根据调用者是不是想要个实例,要的话就创建一个,不要的话就不创建。

public class SingleSimple {
    /**
     * private代表是不向外部暴露出去,
     */
    private static  SingleSimple single=null;
    private SingleSimple(){}//private代表不能new创建该实例。

    public static SingleSimple newInstance(){
        if (single==null) {
              single=new SingleSimple();    
        }
        return single;
    }
}

这是一个超级简单的懒汉单例。

测试:

public class SingleSimpleTest {

    public static void main(String[] args) {

        SingleSimple single01=SingleSimple.newInstance();
        SingleSimple single02=SingleSimple.newInstance();

        System.out.println(single01==single02);
    }

}

运行结果:

这里写图片描述

还是为true说明我们写的懒汉单例没问题。

2 懒汉模式(线程安全)

懒汉模式是根据调用者是不是想要个实例,要的话就创建一个,不要的话就不创建。

public class SingleSimple {
    /**
     * private代表是不向外部暴露出去,
     */
    private static  SingleSimple single=null;
    private SingleSimple(){}//private代表不能new创建该实例。

    public static synchronized SingleSimple newInstance(){
        if (single==null) {
              single=new SingleSimple();    
        }
        return single;
    }
}

这是一个超级简单的懒汉单例。只是加了个同步

测试:

public class SingleSimpleTest {

    public static void main(String[] args) {

        SingleSimple single01=SingleSimple.newInstance();
        SingleSimple single02=SingleSimple.newInstance();

        System.out.println(single01==single02);
    }

}

运行结果:

这里写图片描述

还是为true说明我们写的懒汉单例没问题。

4, 饿汉单例变形(静态代码块)。

静态代码块实现,静态代码块也是随着类加载的。只加载一次

public class SingleSimple {
    /**
     * private代表是不向外部暴露出去,
     */
    private static  SingleSimple single=null;
    private SingleSimple(){}//private代表不能new创建该实例。

    static{
        single=new SingleSimple();
    }
    public static SingleSimple newInstance(){

        return single;
    }
}

测试代码:

public class SingleSimpleTest {

    public static   SingleSimple single01=null;
    public  static  SingleSimple single02=null;
    public static void main(String[] args) {

        single01=SingleSimple.newInstance();
        single02=SingleSimple.newInstance();
        System.out.println(single01==single02);
        System.out.println(single02);
        System.out.println(single01);


    }

}

这里写图片描述

也为true ,说明这也是一种单例。

5, 静态内部类

public class SingleSimple {

    private SingleSimple(){}//private代表不能new创建该实例。

    static class InnerClass{
        private static  SingleSimple single=new SingleSimple();
    }
    public static SingleSimple newInstance(){

        return InnerClass.single;
    }
}

测试代码一样。不贴出来了:

运行结果:

这里写图片描述

还是为true,说明也是单例。

6 , 双重判断。

public class SingleSimple {
    /**
     * private代表是不向外部暴露出去,
     * volatile关键字是代表可见性
     */
    private static volatile SingleSimple single=null;
    private SingleSimple(){}//private代表不能new创建该实例。

    public static SingleSimple newInstance(){
        if (single==null) {
            synchronized (SingleSimple.class) {
                if (single==null) {
                    single=new SingleSimple();  
                }
            }

        }
        return single;
    }
}

在第二个判断时,加了锁,线程是安全的。比第三种实现方式更安全。

测试代码一样,不贴出来了。

运行结果:

这里写图片描述

为true就说明单例是成功的。

7 , 枚举实现

枚举是java1.5才出现的。它也可以实现单例

public enum SingleSimple {
    SINGLE; 
}

测试代码:

public class SingleSimpleTest {

    public static void main(String[] args) {

        SingleSimple S1=SingleSimple.SINGLE;
        SingleSimple S2=SingleSimple.SINGLE;
        System.out.println(S1==S2);
        System.out.println(S1);
        System.out.println(S2);
    }

}

运行结果:

这里写图片描述

为true说明单例成功了。如果不明白枚举的可以去看看。枚举其实挺重要的。

下面我就简单演示下怎么用枚举吧 :

首先是用enum声明的,就这样

public enum SingleSimple {
    SINGLE01,SINGLE02,SINGLE03;
    public void methodInEnum(){
        System.out.println("我是来自枚举中的方法。。。");
    }
}

然后就演示下怎么用枚举。

public class SingleSimpleTest {

    public static void main(String[] args) {

        SingleSimple s1=SingleSimple.SINGLE01;
        SingleSimple s2=SingleSimple.SINGLE02;
        SingleSimple s3=SingleSimple.SINGLE03;
        s1.methodInEnum();//调用枚举中的方法
        int position01=s1.ordinal();//返回的是第几个位置
        int position02=s2.ordinal();//返回的是第几个位置
        int position03=s3.ordinal();//返回的是第几个位置
        System.out.println("SINGLE01的位置"+position01);
        System.out.println("SINGLE02的位置"+position02); 
        System.out.println("SINGLE03的位置"+position03); 
        System.out.println(s1.compareTo(s2));//比较的是位置的大小
        SingleSimple all[]= s1.values();//返回的是SINGLE01,SINGLE02,SINGLE03
        /**
         * 全部打印出来
         */
        for (int i = 0; i <all.length; i++) {
            System.out.println(all[i].name());
        }   
    }
}

运行结果:

这里写图片描述

其实枚举也没什么难度,只有几个方法。我差不多都演示了。

总结:

单例模式我写了七种,目的就是一个,就是在整个应用中只存在一个实例。双重判断现在是用的最多的单例。
最后补充一句:其实反射可以创建实例。即使是构造方法被private修饰,也可以创建一个新实例,但是这样就不能构成单例。反射不会的,应该要加强了。哈哈。。。

  • 3
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 5
    评论
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值