单例设计模式?饿汉式VS懒汉式

hello!铁子,我是Java菜鸟Kerwin,这篇文章视图讲清楚单例设计模式中的饿汉式和懒汉式,如果觉得讲的还算不错,或许可以期待下我日后的Java相关知识分享文章,我们一起进步,不耽误你时间啦,冲冲冲!(真诚欢迎诸位大佬指出文章错误及不当之处,感激不尽)

设计模式简单普及

大白话简单普及下设计模式先;

设计模式就是类似于我们下棋时的常用的经典棋谱,不同的棋局,我们用不同的棋谱,这样就可以省去我们大量的二次思考摸索的时间,而设计模式类似于编程世界的棋谱;

单例设计模式

保证在某个类中只能存在一个对象实例,并且该类只提供一个取得对象实例的方法;

种类:懒汉式、饿汉式、双重检查锁、枚举单例模式、静态内部类单例模式等

实现步骤:(GirlFriend类为例讲解)三步走战略即可实现

  • 1.构造器私有化-
  • 2.类的内部创建对象
  • 3.向外暴露一个静态的公共方法 getInstance
  • 代码实现....
typescript 复制代码
public class Journey {
    public static void main(String[] args) {
       
    }
}

class GirlFriend {
    private String name;

    //2.在类的内部直接创建【静态】对象---为了能够在静态方法中使用,
    //返回gf对象,所以要修饰为static(整家风)
    private static GirlFriend gf = new GirlFriend("小n");

//如何保障我们只能创建一个GirlFriend对象?(保持专一,懂?)三步走战略就可以实现
    //1.构造器私有化,避免在类的外部创建对象(断外念)
    private GirlFriend(String name) {
        this.name = name;
    }
    //3.为了在外边可以使用,提供一个公共的static方法,返回gf对象(开豁口)
    public static GirlFriend getInstance() {
        return gf;
    }
    
}

饿汉式VS懒汉式

总结就是一句话:饿汉子猴急,懒汉子被动

饿汉式

为什么叫饿汉式呢?因为gf对象直接在类中就创建好了,所以只要类一加载,那么这个对象就创建好了,即使没有使用gf对象,它也会被创建,所以叫饿汉式,显得很着急,还没有长大,脑海中就已经幻想拥有了女朋友(怪不得叫饿汉,我都没有这么想过);

typescript 复制代码
public class Journey {
    public static void main(String[] args) {
        //通过方法可以获取对象,
        GirlFriend instance = GirlFriend.getInstance();
        System.out.println(instance);//GirlFriend{name='小n'}
        //即使再获取一个对象,其还是会映射到"小n",这就是单例设计模式的精髓hhhh
        GirlFriend instance2 = GirlFriend.getInstance();
        System.out.println(instance2);//GirlFriend{name='小n'}

        System.out.println(instance2 == instance);//true
    }
}

class GirlFriend {
    private String name;
 
    private static GirlFriend gf = new GirlFriend("小n");

    private GirlFriend(String name) {
        this.name = name;
    }
    //这里如果没有static,你又得自己去new,又回到了之前的循环之中
    public static GirlFriend getInstance() {
        return gf;
    }

    @Override
    //重写个toString方法,把初始化的gf对象的名字打出来
    public String toString() {
        return "GirlFriend{" + "name='" + name + ''' + '}';
    }
}

再补充点细节

arduino 复制代码
 main方法中敲下这行语句:          System.out.println(GirlFriend.age);

    //这行语句实际上没有使用到gf对象,但是在使用静态属性age的时候,会导致GirlFriend类被加           
    //载,一旦类被加载了,则(***)这句静态属性初始化的代码语句是会被执行的,一旦(***)被执 
    //行则有参构造器private GirlFriend(String name) 会被调用,所以会
    //会输出"GirlFriend构造器被调用!!!",而且是先输出


class GirlFriend {
    private String name;
    public static int age=100;
   
    //此中的对象是核心,饿汉式可能造成创建了对象,但是没有使用。
    private static GirlFriend gf = new GirlFriend("小n");//(***)

    private GirlFriend(String name) {
        System.out.println("GirlFriend构造器被调用!!!");
        this.name = name;
    }


    public static GirlFriend getInstance() {//这里如果没有static,你又得自己去new,又回到了之前的循环之中
        return gf;
    }

    @Override
    //重写个toString方法,把初始化的gf对象的名字打出来
    public String toString() {
        return "GirlFriend{" + "name='" + name + ''' + '}';
    }
}

//输出结果如下:
GirlFriend构造器被调用!!!
100
    

饿汉式可能没有去使用一个实例,但是他也会帮你创建了,但是懒汉式单例设计模式就不存在这个问题,你使用的时候才帮你创建(这家伙绝不会主动!!)

懒汉式

csharp 复制代码
public class Journey {
    public static void main(String[] args) {
		//new Cat("大黄");//被private修饰,哪能随便让你创建对象
        
        //使用Cat类的静态属性,此时类已经加载了,但是不同于饿汉式,
        //其并没有创建cat对象,所以不会调用Cat类的构造方法
        System.out.println(Cat.v1);//没有创建Cat对象,默认是null
    
     
    }
}
//希望在程序运行过程中,只能创建一个Cat对象
class Cat{
    private String name;
    public static int v1 =999;
    //步骤
//    2.定义一个静态static属性对象
    private static Cat cat ;
//   1.仍然是构造器先私有化
    private Cat(String name) {
        System.out.println("Cat类的构造器被调用");
        this.name = name;
    }
//    3.提供一个公共的static方法,可以返回一个Cat对象
    public static Cat getInstance(){
        if(cat ==null){
             cat = new Cat("魔拉");
        }
        return cat;
    }
}
//此时输出的结果如下:
999

同样补充下懒汉式的细节

csharp 复制代码
public class Journey {
    public static void main(String[] args) {
        
        //创建了一个实例,进入到getInstance()方法,发现cat为null,
        //然后new一个Cat对象,给你return,此时有了对象之后,
        //就会进入有参构造方法
        Cat instance = Cat.getInstance();
        System.out.println(instance);//尝试打印出此时创建出的猫的信息(if exist)
        
        Cat instance2 = Cat.getInstance();//已经创建了一个实例之后,再尝试创建就会无功而返哟
	    System.out.println(instance2);//此时cat不等于null,就不会新创建啦,依旧打印之前的cat对象的信息
        
        System.out.println(instance2==instance);//返回true
    }
}
//希望在程序运行过程中,只能创建一个Cat对象
class Cat{
    private String name;
    public static int v1 =999;
    //步骤
//    2.定义一个静态static属性对象
    private static Cat cat ;
//   1.仍然是构造器先私有化
    private Cat(String name) {
        System.out.println("Cat类的构造器被调用");
        this.name = name;
    }
//    3.提供一个公共的static方法,可以返回一个Cat对象
    public static Cat getInstance(){
        if(cat ==null){
           cat = new Cat("魔拉");
        }
        return cat;
    }
}

//此时输出结果如下
Cat类的构造器被调用
Cat{name='魔拉'}
Cat{name='魔拉'}
true

懒汉式,只有当用户使用getInstance时,才返回cat对象,后面再次调用时,会返回上次创建的cat对象,从而保证了单例

小结

  • 饿汉式和懒汉式,二者最主要的区别在于创建对象的时机不同:饿汉式是在类加载时就创建了对象实例,而懒汉式是在使用时,才创建对象实例;
  • 饿汉式不存在线程安全问题,懒汉式存在线程安全问题
  • 饿汉式存在浪费资源的可能,因为如果程序员一个对象实例都没有使用,那么饿汉式创建的对象就浪费了,懒汉式是使用时才创建,就不存在这个问题
  • 在JavaSE标准类中,java.lang.Runtime就是经典的单例模式,而且它是饿汉式的单例模式,可以自己查看源码了解(算了,我粘出来给你瞅一眼,粘错了别怪我)
csharp 复制代码
public class Runtime {//Runtim的对应部分源码
    //类加载时就创建对象--->饿汉式
    private static Runtime currentRuntime = new Runtime();

    public static Runtime getRuntime() {
        return currentRuntime;
    }

    private Runtime() {}
}

拜拜啦,希望我的文章对你学习Java或多或少有点帮助,欢迎诸位大佬在评论区留言指出文章的错误或文章讲解存在的问题(我太想进步了啊!!!)

相关推荐
画个大饼1 小时前
Go语言实战:快速搭建完整的用户认证系统
开发语言·后端·golang
iuyou️7 小时前
Spring Boot知识点详解
java·spring boot·后端
一弓虽7 小时前
SpringBoot 学习
java·spring boot·后端·学习
姑苏洛言7 小时前
扫码小程序实现仓库进销存管理中遇到的问题 setStorageSync 存储大小限制错误解决方案
前端·后端
光而不耀@lgy7 小时前
C++初登门槛
linux·开发语言·网络·c++·后端
方圆想当图灵8 小时前
由 Mybatis 源码畅谈软件设计(七):SQL “染色” 拦截器实战
后端·mybatis·代码规范
毅航8 小时前
MyBatis 事务管理:一文掌握Mybatis事务管理核心逻辑
java·后端·mybatis
我的golang之路果然有问题8 小时前
速成GO访问sql,个人笔记
经验分享·笔记·后端·sql·golang·go·database
柏油9 小时前
MySql InnoDB 事务实现之 undo log 日志
数据库·后端·mysql
写bug写bug10 小时前
Java Streams 中的7个常见错误
java·后端