Java 学习笔记——单例设计模式

Java 学习笔记——单例设计模式

概述

概念

单例(Singleton)设计模式是结构最简单的设计模式。其内部只包含一个称为单例类的特殊类。

单例模式的目的是为了确保系统中的一个类只有一个实例,并且这个实例可以很方便的被外界访问。

单例模式的结构

在单例类的内部创建唯一实例,通过静态方法getInstance()使得客户端可以使用它的唯一的实例。同时将构造器私有化,将唯一实例定义为静态对象供外部共享访问

单例模式的适用环境

1)系统只需要一个实例对象,或因为其资源消耗量大,只允许创建一个对象

2)客户调用类的单个实例只允许使用一个公共访问点。

单例模式的实现

单例模式思路分析

1)构造器私有化

2)提供一个该类的静态私有化实例

3)提供一个公有的静态方法,提供该实例

实现方式I:饿汉式
class Singleton{
    //实例化私有的静态成员变量
    private static final Singleton instance = new Singleton();
    //私有化构造器
    private Singleton(){}
    //公有的静态工厂方法
    public static Singleton getInstance(){
        return instance;
    }
}
实现方式II:懒汉式
class Singleton1{
    //私有成员变量
    private volatile static Singleton1 instance = null;
    //私有化构造器
    private Singleton1(){};
    //公有的静态方法
    public static Singleton1 getInstance(){  
        //判断instance是否为空,若不为空则直接返回
        if(instance == null){
            //加锁,实例化instance
            synchronized (Singleton1.class){
                //二次判断(避免多个线程在加锁前均通过第一次判断,因而创建两个实例)
                if(instance == null){
                    //实例化instance
                    instance = new Singleton1(); 
                }
            }
        }
        return instance;
    }

}
两种创建方式对比分析

1)饿汉式:在类加载时就将自己实例化,不存在线程安全的问题,可以确保实例的唯一性;同时调用速度与反应时间也更快。但该实例生命周期长,资源利用效率差。

2)懒汉式:在getInstance方法被调用时才实例化对象,系统资源占用率低。但需要额外处理线程安全问题,效率相对较低。

破坏单例模式的方法

反射

通过反射我们可以获取单例类的构造函数,通过设置setAccessible(true)的方法,可以使我们访问私有的构造方法,这样以来单例模式就有可能被破坏

public class SingletonTesting {
    public static void main(String[] args) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
        Class<SingleTon> clazz = SingleTon.class;
        //通过反射获取单例类的构造器
        Constructor<SingleTon> constructor = clazz.getDeclaredConstructor();
        //禁用安全检查
        constructor.setAccessible(true);
        //创建两个对象
        SingleTon ton1 = constructor.newInstance();
        SingleTon ton2 = constructor.newInstance();
        System.out.println(ton1 == ton2); //控制台输出false,单例模式被破坏
    }
}
序列化:

在序列化,反序列化的过程中,底层也可以通过反射的方式破坏单例模式

public class SingletonTesting {
    public static void main(String[] args) throws IOException, ClassNotFoundException {
        ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("test"));
        SingleTon instance1 = SingleTon.getInstance();
        //对获取的单例对象进行序列化
        out.writeObject(instance1);
        ObjectInputStream in = new ObjectInputStream(new FileInputStream("test"));
        //对获取的单例对象进行反序列化
        SingleTon instance2 = (SingleTon)in.readObject();
        System.out.println(instance1 == instance2);  //控制台输出false,单例模式被破坏
    }
}

防止单例模式被破坏的方法

运用枚举类实现单例模式
enum Singleton3{
    INSTANCE;
    public static  Singleton3 getInstance(){
        return INSTANCE;
    }
}

测试

public static void main(String[] args) throws IOException, ClassNotFoundException {
    ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("test"));
    Singleton3 instance1 = Singleton3.getInstance();
    //对获取的单例对象进行序列化
    out.writeObject(instance1);
    ObjectInputStream in = new ObjectInputStream(new FileInputStream("test"));
    //对获取的单例对象进行反序列化
    Singleton3 instance2 = (Singleton3) in.readObject();
    System.out.println(instance1 == instance2);  //控制台输出true
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值