请稍等 ...
×

采纳答案成功!

向帮助你的同学说点啥吧!感谢那些助人为乐的人

EnumStarvingSingleton实例还是可以创建新的实例

老师你好,我发现你在测试之前编写的恶汉和懒汉单例时,在SimpleDemo里面都是直接打印了constructor.newInstance()的结果,也就是

System.out.println(StarvingSingleton.getInstance());
Class clazz = StarvingSingleton.class;
Constructor constructor = clazz.getDeclaredConstructor();
constructor.setAccessible(true);
System.out.println(constructor.newInstance());

output:
com.imooc.demo.pattern.singleton.StarvingSingleton@e580929
com.imooc.demo.pattern.singleton.StarvingSingleton@1cd072a9

这里的结果确实如你所说两个打印的结果不一样,说明这个StarvingSingleton的实例并不唯一。但是当你测试EnumStarvingSingleton的时候你是又强制转成了EnumStarvingSingleton,然后调用了getInstance()方法

System.out.println(StarvingSingleton.getInstance());

EnumStarvingSingleton enumStarvingSingleton = (EnumStarvingSingleton)constructor.newInstance();
System.out.println(enumStarvingSingleton.getInstance());

output:
com.imooc.demo.pattern.singleton.EnumStarvingSingleton@1cd072a9
com.imooc.demo.pattern.singleton.EnumStarvingSingleton@1cd072a9

这里的结果也确实显示两个实例是同一个。
但是如果我在测试EnumStarvingSingleton的时候不用getInstance()方法,而是直接像你第一次测试的时候直接调用constructor.newInstance(),好像输出的结果还是非同一个实例。这样我还可以创建新的EnumStarvingSingleton实例,而非第一次创建的那个,那这个单例还有意义么?

另外我尝试把你第一次测试StarvingSingleton时用反射创建的实例强制转成StarvingSingleton,然后调用getInstance()方法,具体如下

System.out.println(StarvingSingleton.getInstance());
Class clazz = StarvingSingleton.class;
Constructor constructor = clazz.getDeclaredConstructor();
constructor.setAccessible(true);
StarvingSingleton starvingSingleton = (StarvingSingleton)constructor.newInstance();
System.out.println(starvingSingleton.getInstance());

output:
com.imooc.demo.pattern.singleton.StarvingSingleton@e580929
com.imooc.demo.pattern.singleton.StarvingSingleton@e580929

结果还是相同的,所以我就有些疑惑是不是只要调用getInstance()方法我们就能保证是同一个实例了?

可能写的有点多,过于复杂,希望老师谅解。谢谢。

正在回答 回答被采纳积分+3

4回答

谷杨 2022-03-16 19:01:33

同学理解了么,我刚看到这里,也有同样的疑惑。如果都调用getInstance()方法,就都是同一个实例啊,跟枚举的单例有何区别呢?

0 回复 有任何疑惑可以回复我~
笑看从前小菜哥 2020-08-28 09:03:43

小小的脑袋大大的问号,这种方式好像也避免不了反射的入侵,依然能创建新的实例

0 回复 有任何疑惑可以回复我~
  • 翔仔 #1
    但是能保证成员变量ContainerHolder.HOLDER.instance是单例,这个单例创建出来后,无论序列化和反序列化,或者使用过程中都是同一个,这个单例没法入侵
    回复 有任何疑惑可以回复我~ 2020-08-28 12:54:58
翔仔 2020-07-05 01:30:02
public static BeanContainer getInstance() {
return ContainerHolder.HOLDER.instance;
}

同学你调用的是这个呀,所以还是使用的内部属性。。

0 回复 有任何疑惑可以回复我~
翔仔 2020-07-03 00:23:02

同学好,其实我们主要是为了保证

EnumStarvingSingleton

里面的那个枚举类型的成员变量是单例就可以了,外层是的

EnumStarvingSingleton

是没办法保证单例的,但是它的成员变量可以,而且也改不了

0 回复 有任何疑惑可以回复我~
  • 提问者 hellocp7 #1
    但是好像普通没用使用enum的StarvingSingleton,只要使用getInstance()方法,他返回的实例也是一样的,就像我上面问题最后说的,这是偶然么?
    回复 有任何疑惑可以回复我~ 2020-07-03 15:07:06
  • 所以你写出的这个只能保证内部成员变量中的是单例,外部的并不能保证。
    回复 有任何疑惑可以回复我~ 2021-06-28 23:03:49
  • public class EnumStarvingSingleton {
        public static EnumStarvingSingleton getInstance(){
            return ContainerHolder.HOLDER.instance;
        }
    
        private EnumStarvingSingleton(){
            if(ContainerHolder.HOLDER != null){
                throw new RuntimeException("非法创建");
            }
        }
    
        private enum ContainerHolder{
            HOLDER;
            private EnumStarvingSingleton instance;
    
            ContainerHolder(){
                instance = new EnumStarvingSingleton();
            }
        }
    }
    这样写是不是大家可以更加容易理解一些
    回复 有任何疑惑可以回复我~ 2021-06-28 23:14:49
问题已解决,确定采纳
还有疑问,暂不采纳
意见反馈 帮助中心 APP下载
官方微信