2017-08-25 91 views
4

我很困惑。我在java中发现了很多Singleton设计模式的实现。其中我发现实现的是:单身设计模式java idioma

public class MySingleton { 

    private static class Loader { 
     static MySingleton INSTANCE = new MySingleton(); 
    } 

    private MySingleton() {} 

    public static MySingleton getInstance() { 
     return Loader.INSTANCE; 
    } 
} 

如下解释:https://stackoverflow.com。 现在,如果这个实现应该起作用,为什么不会出现以下情况?

public class MySingleton { 

    private static final MySingleton INSTANCE = new MySingleton(); 

    private MySingleton() {} 

    public static MySingleton getInstance() { 
     return INSTANCE; 
    } 
} 

我搜索围绕Java如何处理初始化,但找不到任何显示后者的代码将无法正常工作。 取而代之的是,我找到了以下内容:stackoverflow.com,它指出每个静态初始化发生在类的静态方法被调用之前,所以当调用访问INSTANCE(getInstance)的唯一方法时,应该初始化包含单例实例的静态字段。 所以是的,我真的很困惑:如果这段代码有效,为什么不使用这个更简单的单例设计模式?

+1

后者确实有效:它是一个* eager *单例,而前者是* lazy *单例。 –

回答

5

这两个工作都是单身人士的有效实施。
第一个使用延迟初始化。
这意味着只有当客户端调用getInstance()时才创建单例。
第二个使用一个渴望的初始化。
这意味着只要类加载器加载MySingleton类,就会创建单例。

在实践中,它并没有太大的区别,因为通常getInstance()和单例类加载通常是耦合的。
确实很少有一个客户类指向一个单例类,而不需要通过getInstance()来请求它的实例。

因此,在一般情况下,更加简洁的第二种方式(热切初始化)应该受到青睐。

+0

关于能够通过反射创建课程的其他实例有什么担忧? – nasukkin

+0

@nasukkin这两个问题都没有解决这个问题,所以它与这个问题无关。 – Andreas

+0

@nasukkin许多事情可能会被反思改变。没有增变器的字段,使用'final'修饰符的字段等等......如果你为客户提供了一个组件,并且你需要/想要保护类定义和对象状态,那么使用单例的枚举是好的,但它肯定是不够的。由于公共组件显然不是问题,所以引用这个问题会比其他问题带来更多的困惑。 – davidxxx

1

Java内置的单例模式实现是enum。当你定义一个enum时,你声明并初始化(又名“枚举”)运行时可能存在的所有实例。原始问题中提供的方法存在漏洞;聪明的用户可以创建你的“单身”类的新的非托管实例。 (我建议你阅读他的例子约书亚布洛赫的“有效的Java”的书就如何可以完成此。)

你应该考虑实现你的单身像这样:

public enum MySingleton { 
    INSTANCE(); 

    /* delcare instance fields here. */ 

    /** constructor; give it params if you need to. */ 
    public MySingleton() { 
     // initialize whatever you need here. 
    } 

    /* methods you'll use go here. */ 
} 

当你需要你的单,您只需将其作为MySingleton.INSTANCE即可。

+0

语法错误:*枚举构造函数的非法修饰符; * – Andreas

+0

@Andreas你得到语法错误,因为你定义了一个enum写INSTANCE; (没有括号) – taran95

+0

@ taran95不,我得到语法错误,因为构造函数是'public',并且只允许'private',*完全像错误说的*。 – Andreas