Java 饿汉式,懒汉式的单例模式(只能获取一个类的一个对象)

Java 饿汉式,懒汉式的单例模式(只能获取一个类的一个对象)


前言

提示:本节内容主要讲解Java中对于一个类只能获取一个对象的方法:分别是单例模式中的饿汉式和懒汉式,基于各自实现的代码以及区别将会在下面一 一讲述。


提示:以下是本篇文章正文内容,下面案例可供参考

一、一个类只能获取一个对象?

这句话的含义是:对于同一个类,不管是子类亦或是其他类,在实例化对象的时候有且只有一个对象,但是可以获取多次,其实也是获取到的是同一个对象。
举个例子:Windows中我们打开任务管理器的时候每次只能打开一个,(快捷键:CTRL + SHIFT + ESC),不会出现多开的情况。

二、实现思路:

  • 如果只让外部获取到一个当前类实例化的对象,那么就不能在外部实例化对象,否则对象的数量将无法控制。所以我们需要将构造方法进行私有化(private)
  • 其次,如果不在外部实例化对象,那么就要在类内部实例化对象,那么就可以将这个对象当做成员变量来看待,那么如何设置成员变量的修饰符呢?应该设置为(private static
  • 为什么这样设计呢?:
  • 首先对于private来说:首先符合我们一贯的编程思维(成员变量私有化,成员方法公有化),其次是减少外部的可见性以及可操作性,这样才能保证我们只实例化一个对象而且永久可用的状态,否则如果是public的,外部可以直接获取到甚至修改对象,就无法保证以上所说的状态了。在饿汉式中也可以添加关键字final,让它是一个永远固定的值,内部也无法再次修改。
  • 其次对于static来说:搭配private后,必须要使用get,set方法进行操作当前成员变量,但是如果不写这些方法的情况下,直接提升为类层级,在外部想要获取当前对象的时候可以不用new对象,直接使用静态方法将对象返回出去,但是静态方法只能调用静态内容,所以将成员变量修改为(static)
  • 最后,编写一个公有的静态成员方法,可以在不创建对象的情况下使用,然后返回当前对象

三,代码实现

3.1 饿汉式
/**
 * @author 云梦归遥
 * @date 2021/11/22 10:05
 * @description 只实例化一个对象,使用饿汉式,单例模式
 */
public class Singleton1 {
    // 1.类内创建一个私有的,静态的类类型的对象
    // 目的:
    // 首先防止外部通过使用 Singleton1.singleton1 = null; 也避免内部修改,直接将对象报废(private,final)
    // 其次是为了在类内部实例化一个对象,提升为类层级,外部便于使用静态方法返回当前对象,因为静态方法只能调用静态内容(static)
    // 饿汉式:
    // 一上来就实例化一个对象,当外部调用 get 方法时直接将对象返回出去
    private final static Singleton1 singleton1 = new Singleton1();

    // 2.私有化构造方法
    // 目的:
    // 只允许在类内实例化对象,如果可以在类外实例化对象,那么对象的数量就无法保证了
    private Singleton1() {

    }

    // 3.提供公有的 get 方法将实例化的对象返回出去
    public static Singleton1 getInstance() {
        return singleton1;
    }
}

3.2 懒汉式
/**
 * @author 云梦归遥
 * @date 2021/11/22 10:15
 * @description 只实例化一个对象,使用懒汉式,单例模式
 */
public class Singleton2 {
    // 1.类内创建一个私有的,静态的类类型的对象
    // 目的:
    // 首先防止外部通过使用 Singleton1.singleton1 = null; 将对象报废(private)
    // 其次是为了在类内部实例化一个对象,提升为类层级,外部便于使用静态方法返回当前对象,因为静态方法只能调用静态对象(static)
    // 懒汉式:
    // 一开始不需要实例化对象,直到外部调用 get 方法的时候才实例化对象并返回出去
    private static Singleton2 singleton2 = null;

    // 2.私有化构造方法
    // 目的:
    // 只允许在类内实例化对象,如果可以在类外实例化对象,那么对象的数量就无法保证了
    private Singleton2() {

    }

    // 3.提供公有的 get 方法将实例化的对象返回出去,synchronized 实行同步代码块,线程安全
    public static synchronized Singleton2 getInstance() {
        if (null == singleton2) {
            singleton2 = new Singleton2();
        }
        return singleton2;
    }
}

3.3 外部代码测试:

/**
 * @author 云梦归遥
 * @date 2021/11/22 10:22
 * @description
 */
public class SingletonTest {

    public static void main(String[] args) {

        // 1.首先测试 饿汉式 的单例模式 创建对象
        Singleton1 singleton11 = Singleton1.getInstance();
        Singleton1 singleton12 = Singleton1.getInstance();
        // 当你使用 IDEA 编写这行代码的时候就会自动提示 这个表达式永远为 true
        System.out.println(singleton11 == singleton12); // true

        System.out.println("===========================");
        // 2.然后测试 懒汉式 的单例模式 创建对象
        Singleton2 singleton21 = Singleton2.getInstance();
        Singleton2 singleton22 = Singleton2.getInstance();
        // 当你编写这行代码的时候不会自动提示,因为在编译器看来
        // getInstance 方法会根据条件 返回不同的值,不是永远返回一个相同的值
        System.out.println(singleton21 == singleton22); // true

        System.out.println("===========================");
        // 不会有小伙伴好奇要比较 懒汉式 和 饿汉式 的对象是否相同吧(这个问题不该问)
        // 3.最后测试 懒汉式 和 饿汉式 两个单例模式 创建的对象 是否相同
        // Error: java: 不可比较的类型: com.lagou.task02.Singleton1和com.lagou.task02.Singleton2
        //System.out.println(singleton11 == singleton21);
        //System.out.println(singleton11 == singleton22);
        //System.out.println(singleton12 == singleton21);
        //System.out.println(singleton12 == singleton22);
    }
}

在这里插入图片描述

四,懒汉式和饿汉式区别

既然懒汉式和饿汉式都可以实现我们的目的,那为什么我们要写两种方式,一种不就解决了吗?接下拉我们来分析一下:
饿汉式:
  • 一上来就实例化一个对象,当外部调用 get 方法时直接将对象返回出去
  • 线程安全,对象早已经实例化好了,因为无论如何都只是同一个对象。
懒汉式:
  • 一开始不需要实例化对象,直到外部调用 get 方法的时候才实例化对象并返回出去
  • 线程不安全,因为不同线程在调用方法时对象状态仍然为null,大家都会实例化对象并返回,从而造成数据不同步,可以加上synchronized关键字实现同步代码块。

总结

以上就是Java实现懒汉式与饿汉式的思路分析,以及代码实现,对于区别,谢谢大家。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值