单例模式

51 阅读3分钟

1.什么是单例模式

单例模式是指,只创建一个类的实例,这个类提供了唯一一种访问这个实例的方式。

2.单例模式的特点

  • 单例类只有一个实例
  • 单例类的实例定义在类内,由该类提供访问方式
  • 单例类的构造函数必须是私有的(私有构造函数只能在类内部被调用)

3.实现单例模式的逻辑

将类的唯一实例作为类的私有静态成员变量封装在类内,并提供访问实例的公有方法,通过类名.方法名()调用

4.单例模式的两种形式

  • 饿汉式:在类加载时(JVM虚拟机执行.class文件)生成类的实例
  • 懒汉式:在首次使用该实例时在生成

5.饿汉式

两种实现方法

  • 用静态成员变量创建类的实例
  • 用静态代码创建类的实例

5.1静态成员变量创建类的实例

需要声明一个私有的静态成员变量并赋值,然后对外暴露出可以公共访问的方式,记得一定要把构造方法私有化

public class Singleton1 {
    private String name;
    private int age;
    private String ID;
    
    private static Singleton1 instance = new Singleton1();//静态成员变量instance作为类的实例
    private Singleton1(){
        this.age=21;
        this.ID="202203180031";
        this.name="Theshy";
    };

    public static Singleton1 getInstance() {
        return instance;
    }
    public String getName(){
        return name;
    }
    public int getAge(){
        return age;
    }
    public String getID(){
        return ID;
    }
}
public class Main {
    public static void main(String[] args) {
        Singleton1 ton1 = Singleton1.getInstance();
        System.out.println(ton1.getAge());
        System.out.println(ton1.getName());
        System.out.println(ton1.getID());
    }
}

5.2在静态代码块中创建类的实例

静态代码块中创建对象,顾名思义,就是在静态代码块中给对象赋值,首先,我们一样要将构造方法私有化,然后在成员变量中声明一个该类的对象,在静态代码块中给对象赋值,最后,只有对外暴露出公共的访问方式即可。

public class Singleton1 {
    
    
    private static Singleton1 instance //静态成员变量instance作为类的实例
   
    public static Singleton1 getInstance() {
        instance = new Singleton1() //在静态代码块中赋值
        return instance;
    }   
}

6.懒汉式

构造函数私有化,在对外暴露的公有函数中创建对象,创建时先判断对象是否被赋值了,若赋值则直接返回,若为未赋值则赋值创建实例

public class Singleton1 {
    
    
    private static Singleton1 instance //静态成员变量instance作为类的实例
    private Singleton1(){};
    public static Singleton1 getInstance() {
      if(instance == null){
        instance = new Singleton1() //在静态代码块中赋值
        }
        return instance;
    }   
}

实际上这种做法是存在问题的,从上面代码我们可以看出该方式在成员位置声明Singleton3类型的静态变量,并没有进行对象的赋值操作,那么什么时候赋值的呢?当调用getInstance()方法获取Singleton3类的对象的时候才创建Singleton3类的对象,这样就实现了懒加载的效果。但是,如果是多线程环境,会出现线程安全问题。

7.加锁

7.1为公有的暴露方式加锁

private static Singleton1 instance //静态成员变量instance作为类的实例
    private Singleton1(){};
    public static synchronized Singleton1 getInstance() {
      if(instance == null){
        instance = new Singleton1() //在静态代码块中赋值
        }
        return instance;
    }