设计模式之-单例模式

一、什么是单例模式

    单例模式属于创建型模式,是Java中最简单,也是最常用的设计模式之一。其本质是一个单一的类,该类负责创建自己的对象,同时确保只有单个对象被创建。这个类提供了一种访问其唯一的对象的方式,可以直接访问,不需要实例化该类的对象。

二、单例模式的特点

    1.该类只能有一个实例。

    2.该类必须自己创建自己的实例。

    3.该类必须给所有其他对象提供这一实例。

三、实现单例的主要思路

    1.构造方法私有化(关键所在,目的是不让其它的类是主动创建该类对象)。

    2.该类内部提供一个静态方法,返回该类对象(全局唯一)。

四、常见应用场景

    1.项目的日志记录。

    2.项目中读取配置文件的对象。

    3.网站的计数器。

    4……

五、单利模式常见的几种实现方式

    1.饿汉式(线程安全,调用效率高,立即加载)

/**
 * @Description 单利模式:饿汉式
 * @Auther: 笑笑
 * @Date: 17:15 2019/4/17
 */
public class Singleton01 {

    //静态变量,类加载的时候会立即创建该类对象,如果用不到,会造成资源浪费
    private static Singleton01 instance = new Singleton01();

    //私有化构造方法
    private Singleton01(){

    }

    //对外提供获得该类唯一对象的方法
    public static Singleton01 getInstance(){
        return instance;
    }

    public static void main(String[] args){
        Singleton01 s1 = Singleton01.getInstance();
        Singleton01 s2 = Singleton01.getInstance();
        System.out.println(s1);
        System.out.println(s2);
    }
}

    2.懒汉式(线程安全,调用效率不高,懒加载)。

/**
 * @Description 单例模式:懒汉式
 * @Auther: 笑笑
 * @Date: 17:23 2019/4/17
 */
public class Singleton02 {

    private static Singleton02 instance;

    private Singleton02(){

    }

    //第一次调用该方法才创建该类对象,提高资源利用效率
    //每次调用该方法都要同步,调用效率低
    public static synchronized Singleton02 getInstance(){
        if(instance == null){
           instance = new Singleton02();
        }
        return instance;
    }

    public static void main(String[] args){
        Singleton02 s1 = Singleton02.getInstance();
        Singleton02 s2 = Singleton02.getInstance();
        System.out.println(s1);
        System.out.println(s2);
    }
}

    3.双重检测锁

/**
 * @Description 单例模式:双重检测锁
 * @Auther: 笑笑
 * @Date: 17:32 2019/4/17
 */
public class Singleton03 {

    private static Singleton03 instance;

    private Singleton03(){}

    public static Singleton03 getInstance(){
        if (instance == null){                   //第一次检查
            synchronized (Singleton03.class){
                if (instance == null){           //第二次检查
                    instance = new Singleton03();
                }
            }
        }
        return instance;
    }

    public static void main(String[] args){
        Singleton03 s1 = Singleton03.getInstance();
        Singleton03 s2 = Singleton03.getInstance();
        System.out.println(s1);
        System.out.println(s2);       
    }

}

    4.静态内部类(懒汉式)

/**
 * @Description 单例模式:静态内部类
 * @Auther: 笑笑
 * @Date: 17:42 2019/4/17
 */
public class Singleton04 {


    private Singleton04(){}

    //加载外部类,不会立即加载内部类,所以可以懒加载对象
    private static class InnerClass{
        private static final Singleton04 instance = new Singleton04();
    }

    public static Singleton04 getInstance(){
        return InnerClass.instance;
    }

    public static void main(String[] args){
        Singleton04 s1 = Singleton04.getInstance();
        Singleton04 s2 = Singleton04.getInstance();
        System.out.println(s1);
        System.out.println(s2);
    }
}

    5.枚举(饿汉式)

/**
 * @Description 单例模式:枚举实现
 * @Auther: 笑笑
 * @Date: 17:49 2019/4/17
 */
public enum Singleton05 {

    //定义枚举元素,这就是一个Singleton05的单例
    INSTANCE;

    public static Singleton05 getInstance(){
        return INSTANCE;
    }

    public static void main(String[] args){
        Singleton05 s1 = Singleton05.getInstance();
        Singleton05 s2 = Singleton05.getInstance();
        System.out.println(s1);
        System.out.println(s2);
    }
}

六、反射方式破解单例模式(除了枚举实现的单例之外)

package com.xiao.designpattern.singletonpattern;

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;

/**
 * @Description 反射破解单例模式
 * @Auther: 笑笑
 * @Date: 20:41 2019/4/21
 */
public class Demo_01 {

    public static void main(String[] args) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {

        System.out.println("*************正常的单例模式*********************");
        Singleton01 s_1 = Singleton01.getInstance();
        Singleton01 s_2 = Singleton01.getInstance();
        System.out.println(s_1);
        System.out.println(s_2);
        System.out.println(s_1 == s_2);//true

        System.out.println("*************反射破解单例*********************");
        Class<Singleton01> clazz = Singleton01.class;
        Constructor<Singleton01> singleton01Constructor = clazz.getDeclaredConstructor(null);//获取私有空参的构造方法
        singleton01Constructor.setAccessible(true);//跳过权限检查,可以获取私有属性和方法
        Singleton01 s1 = singleton01Constructor.newInstance();//反射,使用空参构造创建对象
        Singleton01 s2 = singleton01Constructor.newInstance();
        System.out.println(s1);
        System.out.println(s2);
        System.out.println(s1 == s2);// false , 这样使用反射就破解了单例模式
    }
}

 运行结果如下

*************正常的单例模式*********************
com.xiao.designpattern.singletonpattern.Singleton01@1540e19d
com.xiao.designpattern.singletonpattern.Singleton01@1540e19d
true
*************反射破解单例*********************
com.xiao.designpattern.singletonpattern.Singleton01@677327b6
com.xiao.designpattern.singletonpattern.Singleton01@14ae5a5
false

防止反射破解单例模式,在构造方法中抛出RuntimeException

 private Singleton01(){
        if(instance != null){
            throw new RuntimeException();
        }
    }

 再次运行测试类,结果如下

*************正常的单例模式*********************
com.xiao.designpattern.singletonpattern.Singleton01@1540e19d
com.xiao.designpattern.singletonpattern.Singleton01@1540e19d
true
*************反射破解单例*********************
Exception in thread "main" java.lang.reflect.InvocationTargetException
	at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
	at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
	at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
	at java.lang.reflect.Constructor.newInstance(Constructor.java:423)
	at com.xiao.designpattern.singletonpattern.Demo_01.main(Demo_01.java:26)
Caused by: java.lang.RuntimeException
	at com.xiao.designpattern.singletonpattern.Singleton01.<init>(Singleton01.java:18)
	... 5 more

七、反序列化方式破解单例模式(除了枚举实现的单例之外)

首先,测试的单例类需要实现序列化接口Serializable,最终测试代码如下

package com.xiao.designpattern.singletonpattern;

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;

/**
 * @Description 使用反序列化破解单例模式
 * @Auther: 笑笑
 * @Date: 20:55 2019/4/21
 */
public class Demo_02 {

    public static void main(String[] args) throws Exception {

        System.out.println("*************正常的单例模式*********************");
        Singleton01 s_1 = Singleton01.getInstance();
        Singleton01 s_2 = Singleton01.getInstance();
        System.out.println(s_1);
        System.out.println(s_2);
        System.out.println(s_1 == s_2);

        System.out.println("*************反序列化破解单例*********************");
        //将上面的s_1对象序列化到一个文件中
        FileOutputStream outputStream = new FileOutputStream("G:\\1.txt");
        ObjectOutputStream objectOutputStream = new ObjectOutputStream(outputStream);
        objectOutputStream.writeObject(s_1);
        objectOutputStream.close();
        outputStream.close();

        //从文件中反序列化s_1对象
        ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream("G:\\1.txt"));
        Singleton01 ss_1 = (Singleton01)objectInputStream.readObject();
        objectInputStream.close();
        System.out.println(s_1);
        System.out.println(ss_1);
        System.out.println(s_1 == ss_1);
    }
}

 运行结果如下

*************正常的单例模式*********************
com.xiao.designpattern.singletonpattern.Singleton01@1540e19d
com.xiao.designpattern.singletonpattern.Singleton01@1540e19d
true
*************反序列化破解单例*********************
com.xiao.designpattern.singletonpattern.Singleton01@1540e19d
com.xiao.designpattern.singletonpattern.Singleton01@5fd0d5ae
false

防止反序列化破解单例模式,在单例类中,添加readResolve()方法

 //反序列化时,会直接调用此方法,返回对象,不需要再创建新的对象
    private Object readResolve(){
        return instance;
    }

再次运行测试类,结果如下

*************正常的单例模式*********************
com.xiao.designpattern.singletonpattern.Singleton01@1540e19d
com.xiao.designpattern.singletonpattern.Singleton01@1540e19d
true
*************反序列化破解单例*********************
com.xiao.designpattern.singletonpattern.Singleton01@1540e19d
com.xiao.designpattern.singletonpattern.Singleton01@1540e19d
true

 

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值