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

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

设计模式简单普及

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

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

单例设计模式

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

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

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

  • 1.构造器私有化-

  • 2.类的内部创建对象

  • 3.向外暴露一个静态的公共方法 getInstance

  • 代码实现....

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对象,它也会被创建,所以叫饿汉式,显得很着急,还没有长大,脑海中就已经幻想拥有了女朋友(怪不得叫饿汉,我都没有这么想过);

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 + '\'' + '}';
    }
}


再补充点细节


 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
    


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

懒汉式

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

同样补充下细节

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就是经典的单例模式,而且它是饿汉式的单例模式,可以自己查看源码了解(算了,我粘出来给你瞅一眼)

public class Runtime {//Runtim的对应部分源码
    //类加载时就创建对象--->饿汉式
    private static Runtime currentRuntime = new Runtime();

    public static Runtime getRuntime() {
        return currentRuntime;
    }

    private Runtime() {}
}

拜拜啦,希望我的文章对你学习Java或多或少有点帮助,欢迎在评论区留言指出文章的错误或文章讲解存在的问题,我会努力改进的

  • 5
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值