【java】关于java单例的思考(下)

承接上文!

【java】关于java单例的思考(上) :https://blog.csdn.net/lsr40/article/details/94195394

 

-3.静态内部类模式

该模式也是解决一开始就new对象占用内存的问题,将new对象放到静态内部类中,这样只有实际调用到该静态内部类的时候,才会构造出iceCreamFactory对象,并且也没有线程不安全的问题(由于自始至终类只会加载一次,所以即使在多线程的情况下,也能够保持单例的性质。)

public class IceCreamFactory {
    private IceCreamFactory(){}

    public  static IceCreamFactory getInstance() {
        return IceCreamFactoryHolder.iceCreamFactory;
    }

   private static class IceCreamFactoryHolder{
        private static IceCreamFactory iceCreamFactory = new IceCreamFactory(count);
    }
}

优点:代码量少,较为简单的实现了单例,并且没有线程不安全的问题

缺点:需要多加载一个类,并且静态内部类有着一个致命的缺点,就是传参的问题,由于是静态内部类的形式去创建单例的,故外部无法传递参数(传入构造该对象时候的一些上下文context)进去。所以,如果自己定义的类是单例时,还是要斟酌下使用哪种模式更为合理!

如下代码演示了尝试传参,并且失败的例子:

public class IceCreamFactory {
    private IceCreamFactory(int count){
        System.out.println("外部传入的count:"+count);
    }
    public  static IceCreamFactory getInstance(int count) {
        IceCreamFactoryHolder.count = count;
        System.out.println("input.count:"+count);
        System.out.println("IceCreamFactory.count:"+IceCreamFactoryHolder.count);
        return IceCreamFactoryHolder.iceCreamFactory;
    }
    public  void  printAAFunction(){
        System.out.println("aa");
    };
    private static class IceCreamFactoryHolder{
        static int count;
        private static IceCreamFactory iceCreamFactory = new IceCreamFactory(count);
    }
}


//====================调用===================
public class test {
    public static void main(String[] args) {
        IceCreamFactory iceCreamFactory =  IceCreamFactory.getInstance(100);
        iceCreamFactory.printAAFunction();
    }
}

//==========结果=========
//外部传入的count:0
//input.count:100
//IceCreamFactory.count:100
//aa

 

-4.单例注册表模式

前面说了3种模式,但是真正在做java应用的时候,很少有机会自己写单例。

一般都是spring帮你实现了这些东西(比如你的controller其实默认是单例的,当然也可以设置成不是单例,这里就不再多讲了,可以百度到相关的知识的:https://www.cnblogs.com/maohuidong/p/7837688.html(作者:毛会懂))

那么相信大家会有和我一样的疑惑,那spring实现单例又是什么模式呢?

对的,就是这个单例注册表模式!

大概讲下,其实就是直接new一个ConcurrentHashMap,然后当调用到了某个单例对象的时候,就去map里面寻找,有的话直接返回,没有就创建,并添加该对象到map中!(这也是一种很好的思路,当你的需要设置单例的类比较多的时候)

//在DefaultSingletonBeanRegistry类中,85行有着如下代码

/** Cache of singleton objects: bean name --> bean instance */
	private final Map<String, Object> singletonObjects = new ConcurrentHashMap<String, Object>(256);

//调用这个map的代码在AbstractBeanFactory类中的235行的doGetBean方法

protected <T> T doGetBean(
			final String name, final Class<T> requiredType, final Object[] args, boolean typeCheckOnly)
			throws BeansException {

//具体代码我就不贴出来了,大家有兴趣可以去研究
}

如果大家想看关于这方面的知识,可以自行百度或者观看如下网址:

https://www.cnblogs.com/zhaww/p/8467196.html?tdsourcetag=s_pcqq_aiomsg

https://www.codercto.com/a/4924.html

那,我也来写个例子:

public class SingleRegisterMap {
    /** Cache of singleton objects: bean name --> bean instance */
    private static final Map<String, Object> singletonObjects = new ConcurrentHashMap<String, Object>(256);
    private volatile static SingleRegisterMap singleRegisterMap;

    //获取SingleRegisterMap单例的方法,如果为调用该方法singleRegisterMap这个变量为null
    public  static SingleRegisterMap getInstance() {
        if (singleRegisterMap == null) {
            synchronized (IceCreamFactory.class) {
                if (singleRegisterMap == null) {
                    singleRegisterMap = new SingleRegisterMap();
                }
            }
        }
        return singleRegisterMap;
    }

    private SingleRegisterMap(){
    }

    //获得Map中bean的方法
    public  static Object getBean(String name) {
        //传入的name为空,直接返回空
        if(name != null) {
            synchronized (SingleRegisterMap.class) {
                //name不为空,判断map中是否有该对象,有就返回,没有就创建再返回
                if (singletonObjects.get(name) == null) {
                    try {
                        singletonObjects.put(name, Class.forName(name).newInstance());
                        return  singletonObjects.get(name);
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                } else {
                    return  singletonObjects.get(name);
                }
            }
        }
        return null;
    }
}




//======================测试==========================
//=================随便建一个Dog类=====================
public class Dog {
}
//===================================================
public class test {
    public static void main(String[] args) {
        Dog a =  (Dog)SingleRegisterMap.getBean("com.Dog");
        System.out.println( a instanceof Dog);
        Dog b =  (Dog)SingleRegisterMap.getBean("com.Dog");
        System.out.println(a);
        System.out.println(b);
    }
}
//===============结果(两个dog对象是一样的)================
//true
//com.Dog@12bb4df8
//com.Dog@12bb4df8

优点:可以让getBean传入更多的参数,用于构建不同的Dog对象(可以传context构建单例),并且想拿同一个对象就拿同一个对象,那拿不同的对象就拿不同的对象,还是很方便的

缺点:代码多了那么一点点,并且getBean要考虑通用性~嘿嘿(我个人觉得这种模式还是很666的)

 

好了,到此我要说的单例的4种模式都说完了,还是老话,菜鸡一只,如果有说错的地方,还请大家批评指正,坚决不能写那种不清不楚的文章来误导他人!!!

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值